题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和
此生无悔入东方,来世愿生幻想乡
首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改
用动态树分治就好了嘛。。。
每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本
然后一直向上扫到根就能统计了
↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧
然后就好搞了。。。
对于分治结构的每一个点,我们枚举它的出边
如果某条出边连向的点的距离之和小于当前点,那么答案一定在那条出边指向的子树中,分治做下去就行了
如果不存在小于当前点的出边,那么当前点就是重心
注意区分【出边指向的点】和【分治子节点】的区别= =
时间复杂度O(nlog^2n*20)
求两点间距离要用RMQLCA否则复杂度多个log BZ上过不去
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; int n,m; namespace Tree{ struct abcd{ int to,f,next; bool ban; }table[M<<1]; int head[M],tot=1; int fa[M],dpt[M],dis[M]; int log_2[M<<1],pos[M],a[M<<1][20]; void Add(int x,int y,int z) { table[++tot].to=y; table[tot].f=z; table[tot].next=head[x]; head[x]=tot; } void DFS(int x) { static int T=0; int i; dpt[x]=dpt[fa[x]]+1; a[pos[x]=++T][0]=dis[x]; for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x]) { fa[table[i].to]=x; dis[table[i].to]=dis[x]+table[i].f; DFS(table[i].to); a[++T][0]=dis[x]; } } void Build_LCA() { int i,j; for(i=2;i<=n-1<<1;i++) log_2[i]=log_2[i>>1]+1; for(j=1;j<=log_2[n-1<<1];j++) for(i=1;i+(1<<j)-1<=n-1<<1;i++) a[i][j]=min(a[i][j-1],a[i+(1<<j-1)][j-1]); } int LCA_Distance(int x,int y) { x=pos[x];y=pos[y]; if(x>y) swap(x,y); int l=log_2[y-x+1]; return min(a[x][l],a[y-(1<<l)+1][l]); } int Distance(int x,int y) { return dis[x]+dis[y]-2*LCA_Distance(x,y); } } namespace Dynamic_TDC{ struct abcd{ int to,first,next; }_table[M]; int _head[M],_tot; int root,fa[M]; long long dis_sum1[M],dis_sum2[M],sum1[M],sum2[M]; void Add(int x,int y,int z) { _table[++_tot].to=y; _table[_tot].first=z; _table[_tot].next=_head[x]; _head[x]=_tot; } int Get_Size(int x,int from) { int i,size=1; for(i=Tree::head[x];i;i=Tree::table[i].next) { if(Tree::table[i].ban) continue; if(Tree::table[i].to==from) continue; size+=Get_Size(Tree::table[i].to,x); } return size; } int Get_Centre_Of_Gravity(int x,int from,int size,int &cg) { int i,re=1,flag=1; for(i=Tree::head[x];i;i=Tree::table[i].next) { if(Tree::table[i].ban) continue; if(Tree::table[i].to==from) continue; int temp=Get_Centre_Of_Gravity(Tree::table[i].to,x,size,cg); if(temp<<1>size) flag=0; re+=temp; } if(size-re<<1>size) flag=0; if(flag) cg=x; return re; } int Tree_Divide_And_Conquer(int x) { int i,size=Get_Size(x,0); Get_Centre_Of_Gravity(x,0,size,x); for(i=Tree::head[x];i;i=Tree::table[i].next) { if(Tree::table[i].ban) continue; Tree::table[i].ban=true; Tree::table[i^1].ban=true; int temp=Tree_Divide_And_Conquer(Tree::table[i].to); fa[temp]=x; Add(x,temp,Tree::table[i].to); } return x; } void Modify(int x,int delta) { int i; sum1[x]+=delta; for(i=x;fa[i];i=fa[i]) { int dis=Tree::Distance(x,fa[i]); dis_sum1[fa[i]]+=(long long)dis*delta; dis_sum2[i]+=(long long)dis*delta; sum1[fa[i]]+=delta; sum2[i]+=delta; } } long long Calculate(int x) { int i; long long re=dis_sum1[x]; for(i=x;fa[i];i=fa[i]) { int dis=Tree::Distance(x,fa[i]); re+=dis_sum1[fa[i]]-dis_sum2[i]; re+=(sum1[fa[i]]-sum2[i])*dis; } return re; } long long Query(int x) { int i; long long cost=Calculate(x); for(i=_head[x];i;i=_table[i].next) { long long temp=Calculate(_table[i].first); if(temp<cost) return Query(_table[i].to); } return cost; } } namespace IStream{ #define L (1<<16) char Get_Char() { static char buffer[L],*S,*T; if(S==T) { T=(S=buffer)+fread(buffer,1,L,stdin); if(S==T) return EOF; } return *S++; } int Get_Int() { bool flag=false; char c; int re=0; do c=Get_Char(); while((c<'0'||c>'9')&&c!='-'); if(c=='-') flag=true,c=Get_Char(); while(c>='0'&&c<='9') re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char(); return flag?-re:re; } } struct OStream{ char buffer[L],*S; OStream() { S=buffer; } void Put_Char(char c) { *S++=c; if(S==buffer+L) fwrite(buffer,1,L,stdout),S=buffer; } void Put_Long_Long(long long x) { static int stack[20],top; if(!x) stack[++top]='0'; while(x) stack[++top]=x%10+'0',x/=10; while(top) Put_Char(stack[top--]); Put_Char('\n'); } ~OStream() { fwrite(buffer,1,S-buffer,stdout); } }os; int main() { using namespace IStream; int i,x,y,z; cin>>n>>m; for(i=1;i<n;i++) { x=Get_Int(); y=Get_Int(); z=Get_Int(); Tree::Add(x,y,z); Tree::Add(y,x,z); } Tree::DFS(1); Tree::Build_LCA(); Dynamic_TDC::root=Dynamic_TDC::Tree_Divide_And_Conquer(1); for(i=1;i<=m;i++) { x=Get_Int();y=Get_Int(); Dynamic_TDC::Modify(x,y); long long temp=Dynamic_TDC::Query(Dynamic_TDC::root); os.Put_Long_Long(temp); } return 0; }
BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治
原文地址:http://blog.csdn.net/popoqqq/article/details/44872857