树链剖分学习 (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;}
阅读全文
0 0
- 树链剖分学习 (hdu3966)
- HDU3966(树链剖分)
- 树链剖分(hdu3966)
- hdu3966(树链剖分)
- hdu3966 树链剖分(入门,点)
- HDU3966(树链剖分)
- hdu3966 树链剖分
- HDU3966【树链剖分】。
- HDU3966 树链剖分
- [HDU3966]Aragorn's Story(树链剖分)
- hdu3966 Aragorn's Story(树链剖分)
- hdu3966 or hdu5044 树链剖分
- 树链剖分+点权+hdu3966
- hdu3966 树链剖分入门题
- HDU3966(树链剖分) 模板题
- hdu3966 树链剖分入门题
- HDU3966(树链剖分(点权)入门)链分治
- hdu3966 树链剖分(区间更新和单点求值)
- 剑指offer—链表中倒数第K个结点
- vs2010发布包修改发布名称
- HDU2051
- JAVA基础篇-发展史
- 有监督学习和无监督学习
- 树链剖分学习 (hdu3966)
- QuickTest 检查点种类(一)
- 设计模式系列一: 策略模式
- 696. Count Binary Substrings
- 负进制转换
- 每日复习面试题
- C语言——堆栈
- CodeForces 144C
- R paste()函数的使用