树链剖分学习 (hdu3966)

来源:互联网 发布:三维动画软件图标 编辑:程序博客网 时间:2024/06/06 05:24

题意:一棵树上每个节点有权值,定义三种操作:

Q  a  询问a号节点的权值

I  a  b  c    a到b路径上所有节点权值加上c(包括a,b)

D  a  b  c    a到b路径上所有节点权值减去c(包括a,b)

对每个Q,输出结果


树链剖分:将树上的节点(或者边)通过特殊的dfs表上序号,序号作为下标套上线段树。

特殊的dfs :  将边分为重边跟轻边,dfs时优先走重边.

重边:一个节点的连接的子树节点最多的边为重边

修改操作:若当前询问点为a , b    ,  fa,fb为a,b所在重链的最顶端且depth[fb]>depth[fa],则一次修改fb到b区间的数据,在使b=father[b] 直到 fa=fb

正确性:因为dfs 重链优先,则fb到b的上的节点的下标是连续的,修改则就跟线段树的修改一样 ,最坏情况执行log(n)次(a或b最多提升log(n)次到根节点)

接下来就是一般的线段树的操作了。


#include <iostream>using namespace std;#define M 100005#include <string.h>#include <string>struct edges{int x,y,v,next;}edge[M*2];int head[M],num,z;int tree[M*4],w[M],lazy[M*4];int ted[M][3];inline max(int a,int b){return a>b?a:b;}void add_edge(int x,int y,int v){edge[num].x=x;edge[num].y=y;edge[num].v=v;edge[num].next=head[x];head[x]=num++;}int top[M],fat[M],son[M],siz[M],dep[M];int n,m,q;int dfs(int f,int t){fat[t]=f;dep[t]=dep[f]+1;siz[t]=1;son[t]=0;int i=head[t];int mx=0,sum=0;while(i){if(edge[i].y!=f){siz[t]+=dfs(t,edge[i].y);if( siz[son[t]] < siz[edge[i].y] )son[t]=edge[i].y;}i=edge[i].next;}return sum;}void  dfs2(int r,int st){top[r]=st;w[r]=++z;if( son[r] ) dfs2(son[r],st);int i=head[r];while(i){int j=edge[i].y;if( j!=son[r] && j!=fat[r] )dfs2( j , j );i=edge[i].next;}}int nux[M];void pushup(int root){tree[root]=max(tree[root<<1],tree[root<<1+1]);}void pushdown(int root,int v){if(lazy[root]){int l=root<<1,r=l+1,s=lazy[root];lazy[root]=0;lazy[l]+=s;lazy[r]+=s;tree[l]+=(v-v/2)*s;tree[r]+=v/2*s;}}void update2(int root,int low,int row,int l,int r,int v){if(l<=low && r>=row ){lazy[root]+=v;tree[root]+=v*(r-l+1);return ;}if(row<l  || low>r)return ;int ql=root*2,qr=ql+1,mid=(low+row)/2;pushdown(root,row-low+1);update2(ql,low,mid,l,r,v);update2(qr,mid+1,row,l,r,v);pushup(root);}void change(int l,int r,int v){while(top[l]!=top[r]){if( dep[top[l]] > dep[top[r]] ) swap(l,r);update2(1,1,z,w[top[r]],w[r],v);r=top[r];}if(dep[l]>dep[r])  swap(l,r);update2(1,1,z,w[l],w[r],v);}int mfind2(int root,int low,int hig,int loc){if( low==hig )return tree[root];pushdown(root,hig-low+1);int mid=(low+hig)/2,ret;if(loc<=mid) ret=mfind2(root*2,low,mid,loc);else ret=mfind2(root*2+1,mid+1,hig,loc);pushup(root);return ret;}/*---------------------------------------------------*/void init2(){int i,k,x,y;siz[0]=fat[0]=z=0,num=1;memset(head,0,sizeof(head));memset(top,0,sizeof(top));memset(son,0,sizeof(son));memset(tree,0,sizeof(tree));memset(lazy,0,sizeof(lazy));for(i=1;i<=n;i++)cin>>nux[i];for(i=1;i<=m;i++){cin>>x>>y;add_edge(x,y,0);add_edge(y,x,0);}dfs(0,1);dfs2(1,1);for(i=1;i<=n;i++)update2(1,1,z,w[i],w[i],nux[i]);//for(i=1;i<=n;i++)//cout<<son[i]<<' '<<top[i]<<' '<<fat[i]<<' '<<w[i]<<endl;}void work2(){string ques;int a,b,c;while(q--){cin>>ques;if(ques[0]=='Q'){cin>>a;cout<<mfind2(1,1,z,w[a])<<endl;}else {cin>>a>>b>>c;if(ques[0]=='D')c=-c;change(a,b,c);}}}int main(){while(cin>>n>>m>>q){init2();work2();}return 0;}


原创粉丝点击