Description
傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。
在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有\(n\)块空地,这些空地被\(n-1\)条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。
在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点\(u\)上,并且空地v上有\(dv\)个单位的军队,那么幽香每天就要花费\(dv*dist(u,v)\)的金钱来补给这些军队。
由于幽香需要补给所有的军队,因此幽香总共就要花费为\(\sum Dv*dist(u,v)\) (\(1\leq V \leq N\))的代价。其中\(dist(u,v)\)表示u个v在树上的距离(唯一路径的权和)。
因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。
但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。
Solution
题意:树上点权修改,询问带权重心
大大加深了对点分树的理解?
首先,点分树有个性质:点分树上的两点的lca在原树的两点路径上,这样,我们通过记录点分树上一点到它的祖先的在原树上的距离,就可以得到任意两点在原树上的距离啦
带权重心是什么咧?
可以当做它是这样一个点,已这个点为根的每个子树的权重都不超过原树的总size的一半。
为什么?假如找到了这个点,那么无论把它移动进入哪个子树,代价都会变得更大,读者可以自行证明。
而我们用上面的做法,就可以得到树的带权重心。
对于这道题:
先预处理出点分树,记录下每个点在点分树上的孩子和祖先以及和每个祖先的实际距离(便于以后查找)
记录下点分树上每个节点,在原树上所代表的联通块的根节点\(HR\)(这里指的是深度最小的那个点)
为什么要记录这个东西咧?
因为我们在寻找带权重心的时候,每进入一个点,就要更改某些点的权重,因为要算上除了这个联通块外的权重,而需要更改的点就是这个\(HR\),可以理解为,它是这个联通块的边界
当然找到重心后,你得把你做的更改全都改回来
我们考虑每次更改会有什么影响,首先,总权重增加\(e\),点分树上的相关节点的总权重也会发生变化,还有就是要即使更新相关节点的代价和,具体的,加上\(e*dis\),这里的相关节点指的是修改节点的祖先节点(我们显然只需要记录它对祖先的贡献,根据点分树的性质)
查询就是枚举这个点与重心的在点分树上的\(lca\),统计代价即可
因为点分树的深度不超过\(\log n\),所以总复杂度是\(O(n log^2 n)\)
Code
#include#define ll long long#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f;}#define MN 100005#define reg registerint n,m,en,hr[MN];struct edge{int to,w,nex;}e[MN<<1];inline void ins(int f,int t,int w){ e[++en]=(edge){t,w,hr[f]};hr[f]=en; e[++en]=(edge){f,w,hr[t]};hr[t]=en;}bool vis[MN];int rt,sm,siz[MN],dep[MN];ll vsum,w[MN],val[MN];struct Node{int id;ll dis;};std::vector fa[MN],s[MN];int HR[MN];void pre_dfs(int x,int f){ reg int i;siz[x]=1; for(i=hr[x];i;i=e[i].nex)if(!vis[e[i].to]&&(f^e[i].to)) pre_dfs(e[i].to,x),siz[x]+=siz[e[i].to];}void getroot(int x,int f){ reg int i;rt=x; for(i=hr[x];i;i=e[i].nex) if(!vis[e[i].to]&&(f^e[i].to)&&(siz[e[i].to]<<1)>=sm){getroot(e[i].to,x);break;}}void dfs(int x,int f,int ro){ fa[x].push_back((Node){ro,dep[x]}); reg int i; for(i=hr[x];i;i=e[i].nex)if(!vis[e[i].to]&&(f^e[i].to)) dep[e[i].to]=dep[x]+e[i].w,dfs(e[i].to,x,ro);}inline void pre_work(int x=1,int f=0){ pre_dfs(x,f); sm=siz[x];getroot(x,f);vis[rt]=true; reg int i,j=rt; s[f].push_back((Node){j,0LL});fa[j].push_back((Node){j,0LL}); HR[j]=x; for(i=hr[rt];i;i=e[i].nex) if(!vis[e[i].to]){dep[e[i].to]=e[i].w;dfs(e[i].to,j,j);pre_work(e[i].to,j);} rt=j;}inline void Modify(int x,int y){ vsum+=y;val[x]+=y;reg int i,j=x,f,k; for(i=fa[x].size()-1;~i;--i) w[fa[x][i].id]+=y; for(i=fa[x].size()-2;~i;--i) for(j=s[fa[x][i].id].size()-1;~j;--j) if(s[fa[x][i].id][j].id==fa[x][i+1].id){s[fa[x][i].id][j].dis+=y*fa[x][i].dis;break;}}inline void upd(int x,int y){for(reg int i=fa[x].size()-1;~i;--i)w[fa[x][i].id]+=y;}inline int Find(int x){ reg int ret=x,i,tmp; for(i=s[x].size()-1;~i;--i) if(w[s[x][i].id]*2>=vsum) { tmp=w[x]-w[s[x][i].id]; upd(HR[s[x][i].id],tmp);ret=Find(s[x][i].id);upd(HR[s[x][i].id],-tmp); break; } return ret;}inline ll Query(int x){ reg ll ret=0; reg int i,j,las=0; for(i=fa[x].size()-1;~i;las=fa[x][i].id,--i) { ret+=fa[x][i].dis*val[fa[x][i].id]; for(j=s[fa[x][i].id].size()-1;~j;--j) if(s[fa[x][i].id][j].id^las) ret+=fa[x][i].dis*w[s[fa[x][i].id][j].id]+s[fa[x][i].id][j].dis; } return ret;}int main(){ n=read();m=read(); register int i,x,y; for(i=1;i
Blog来自PaperCloud,未经允许,请勿转载,TKS!