标签:树链剖分
3 2 5 1 2 3 2 1 2 3 I 1 3 5 Q 2 D 1 2 2 Q 1 Q 3
7 4 8Hint1.The number of enemies may be negative. 2.Huge input, be careful.
题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
分析:典型的树链剖分题目,先进行剖分,然后用线段树去维护即可,注意HDU的OJ采用Windows系统,容易爆栈,所以在代码
前面加上:#pragma comment(linker, "/STACK:1024000000,1024000000")进行手动扩栈。
#pragma comment(linker, "/STACK:1024000000,1024000000") //因OJ采用Windows系统,要加入这一行用于 进行手动扩栈,这样就不会引起爆栈 #include<stdio.h> #include<string.h> #include<vector> using namespace std; const int N = 50015; vector<int>mapt[N]; int fath[N],deep[N],top[N],num[N],son[N],p[N],pos; void init(int n) { pos=0; //memset(son,-1,sizeof(son)); for(int i=0;i<=n;i++) mapt[i].clear(); } void dfs(int u,int pre,int d) { fath[u]=pre; num[u]=1; deep[u]=d; son[u]=-1; int k=mapt[u].size(); for(int i=k-1;i>=0;--i) { int v=mapt[u][i]; if(v==pre)continue; dfs(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[son[u]]<num[v]) son[u]=v; } } void getpos(int u,int root) { top[u]=root; p[u]=++pos;//从1开始 if(son[u]==-1) return ; getpos(son[u],root); int k=mapt[u].size(); for(int i=k-1;i>=0;--i) { int v=mapt[u][i]; if(son[u]==v||v==fath[u]) continue; getpos(v,v); } } struct tree { int allnum,addnum; }root[N*3]; int a[N]; void build(int l,int r,int k) { root[k].addnum=0; if(l==r){ root[k].allnum=a[l]; return ; } int mid=(l+r)/2; build(l,mid,k<<1); build(mid+1,r,(k<<1)|1); root[k].allnum=root[k<<1].allnum+root[(k<<1)|1].allnum; } void upson(int l,int r,int k) { int mid=(l+r)/2; if(root[k].addnum){ root[k<<1].allnum+=(mid-l+1)*root[k].addnum; root[k<<1].addnum+=root[k].addnum; root[(k<<1)|1].allnum+=(r-mid)*root[k].addnum; root[(k<<1)|1].addnum+=root[k].addnum; root[k].addnum=0; } } void update(int l,int r,int k,int L,int R,int c) { if(L<=l&&r<=R) { root[k].allnum+=(r-l+1)*c; root[k].addnum+=c; return ; } int mid=(l+r)/2; upson(l,r,k); if(L<=mid) update(l,mid,k<<1,L,R,c); if(mid<R) update(mid+1,r,(k<<1)|1,L,R,c); root[k].allnum=root[k<<1].allnum+root[(k<<1)|1].allnum; } int query(int l,int r,int k,int id) { if(l==r) return root[k].allnum; upson(l,r,k); int mid=(l+r)/2; if(id<=mid) return query(l,mid,k<<1,id); else return query(mid+1,r,(k<<1)|1,id); } void swp(int &a,int &b) { int tt=a; a=b; b=tt; } void Operat(int u,int v,int c) { int fu=top[u], fv=top[v]; while(fu!=fv) { if(deep[fu]<deep[fv]) { swp(fu,fv); swp(u,v); } update(1,pos,1,p[fu],p[u],c); u=fath[fu]; fu=top[u]; } if(deep[u]>deep[v]) swp(u,v); update(1,pos,1,p[u],p[v],c);//点权更新与边权更新的区别之一:点p[u],边p[son[u]] } int main() { int n,m,q,val[N]; while(scanf("%d%d%d",&n,&m,&q)>0) { init(n); for(int i=1;i<=n;i++) scanf("%d",&val[i]); while(m--) { int u,v; scanf("%d%d",&u,&v); mapt[u].push_back(v); mapt[v].push_back(u); } dfs(1,1,1); getpos(1,1); for(int i=1;i<=n;i++) a[p[i]]=val[i]; //一定要注意转换成在线段树上的对应位置 pos=n; build(1,pos,1); while(q--) { int u,v,c; char ch[10]; scanf("%s%d",ch,&u); if(ch[0]=='Q') printf("%d\n",query(1,pos,1,p[u])); else { scanf("%d%d",&v,&c); if(ch[0]=='D') c=-c; Operat(u,v,c); } } } return 0; }
HDU 3966Aragorn's Story(树链剖分)点权更新模板
标签:树链剖分
原文地址:http://blog.csdn.net/u010372095/article/details/45534491