BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治

来源:互联网 发布:快手扫号软件 编辑:程序博客网 时间:2024/05/17 04:34

题目大意:给定一棵树,每个点有一个点权,多次改变某个点的点权,多次查询带权重心到所有点的带权距离之和

此生无悔入东方,来世愿生幻想乡


首先我们考虑如何计算一个点到所有点的带权距离之和且支持修改

用动态树分治就好了嘛。。。

每个点记录子树中带权距离之和,以及权值之和,再在每个子树中记录一个需要减掉的版本

然后一直向上扫到根就能统计了

↑这段话面对会写动态树分治的人,不会的先去切捉迷藏吧


然后就好搞了。。。

对于分治结构的每一个点,我们枚举它的出边

如果某条出边连向的点的距离之和小于当前点,那么答案一定在那条出边指向的子树中,分治做下去就行了

如果不存在小于当前点的出边,那么当前点就是重心

注意区分【出边指向的点】和【分治子节点】的区别= =


时间复杂度O(nlog^2n*20)

求两点间距离要用RMQLCA否则复杂度多个log BZ上过不去


#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100using 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;}


1 0
原创粉丝点击