Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Posted DCD暗夜殇
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组相关的知识,希望对你有一定的参考价值。
Aragorn‘s Story
来源:http://120.78.128.11/Problem.jsp?pid=2710 来源:http://acm.hdu.edu.cn/showproblem.php?pid=3966
这题就是一个模板题,模板调过了就可以过
#pragma comment(linker, "/STACK:102400000,102400000") #include<stdio.h> #include<string.h> #include<algorithm> #define mid ((node[now].l+node[now].r)>>1) #define lson node[now].l, mid, now<<1 #define rson mid+1, node[now].r, now<<1^1 #define Q(A, B) memset(A, B, sizeof(A)) using namespace std; const int N=50505; const int INF=0x3f3f3f3f; typedef int mint; mint fa[N], siz[N], dep[N], son[N]; mint id[N], top[N], self[N], cnt; /** siz[u] 保存以u为根的子树节点个数 top[u] 保存当前节点所在链的顶端节点 son[u] 保存重儿子 dep[u] 保存结点u的深度值 fa[u] 保存结点u的父亲节点 id[u] 保存树中每个节点剖分以后的新编号(DFS的执行顺序) self[u] 保存当前节点在树中的位置 **/ mint sz, head[N]; mint sav[N]; mint n, mod; void read(int &x) { int f=1;x=0;char s=getchar(); while(s<‘0‘|s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} x*=f; } mint Max(mint a, mint b) { return a>b?a:b; } mint Min(mint a, mint b) { return a<b?a:b; } struct Ed { int to, next; }E[N*2]; void insert_E(int u, int v) { E[sz].to=v; E[sz].next=head[u]; head[u]=sz++; } struct No { mint ret; struct no { mint l, r, sum, mins, maxn, lazy, lazyset; }node[N<<2]; void build(int L, int R, int now)///建树 { node[now].lazy=0; node[now].lazyset=0; node[now].l=L; node[now].r=R; if(L==R) node[now].mins=node[now].maxn=node[now].sum=self[L]; else { build(L, mid, now<<1); build(mid+1, R, now<<1^1); pushup(now); } } void pushup(int now) { node[now].sum=node[now<<1].sum+node[now<<1^1].sum; node[now].maxn=Max(node[now<<1].maxn, node[now<<1^1].maxn); node[now].mins=Min(node[now<<1].mins, node[now<<1^1].mins); } void pushdown(int now) { if (node[now].lazy) { int len=node[now].r-node[now].l+1; node[now<<1].lazy+=node[now].lazy; node[now<<1^1].lazy+=node[now].lazy; node[now<<1].sum+=node[now].lazy*(len-(len>>1)); node[now<<1^1].sum+=node[now].lazy*(len>>1); node[now<<1].maxn+=node[now].lazy; node[now<<1^1].maxn+=node[now].lazy; node[now<<1].mins+=node[now].lazy; node[now<<1^1].mins+=node[now].lazy; node[now].lazy=0; } } void pushdown_set(int now) { if (node[now].lazyset) { int len=node[now].r-node[now].l+1; node[now<<1].lazyset=node[now].lazyset; node[now<<1^1].lazyset=node[now].lazyset; node[now<<1].sum=node[now].lazyset*(len-(len>>1)); node[now<<1^1].sum=node[now].lazyset*(len>>1); node[now<<1].maxn=node[now].lazyset; node[now<<1^1].maxn=node[now].lazyset; node[now<<1].mins=node[now].lazyset; node[now<<1^1].mins=node[now].lazyset; node[now].lazyset=0; } } void update(int L, int R, mint v, int now)///区间更新 { if(L<=node[now].l&&node[now].r<=R) { node[now].lazy+=v; node[now].sum+=(node[now].r-node[now].l+1)*v; node[now].maxn+=v; node[now].mins+=v; return ; } pushdown(now); if(L<=mid) update(L, R, v, now<<1); if(R>mid) update(L, R, v, now<<1^1); pushup(now); } mint query(int L, int R, int now)///区间求和 { if(L<=node[now].l&&R>=node[now].r) return node[now].sum; pushdown(now); mint ret=0; if(L<=mid) ret+=query(L, R, now<<1); if(R>mid) ret+=query(L, R, now<<1^1); return ret; } void addn(int now)///将1~n的节点里的值保存到一个sav[]数组里 { for(mint i=node[now].l; i<=node[now].r; i++) sav[i]+=node[now].sum; if(node[now].l==node[now].r) return; addn(now<<1); addn(now<<1^1); } mint querymin(int L,int R,int now)///L~R的最小值 { if(L<=node[now].l&&R>=node[now].r) return node[now].mins; pushdown(now); if(L<=mid) ret=Min(ret, querymin(L,R,now<<1)); if(R>mid) ret=Min(ret, querymin(L,R,now<<1^1)); return ret; } mint querymax(int L,int R,int now)///L~R的最大值 { if(L<=node[now].l&&R>=node[now].r) return node[now].maxn; pushdown(now); if(L<=mid) ret=Max(ret, querymax(L,R,now<<1)); if(R>mid) ret=Max(ret, querymax(L,R,now<<1^1)); return ret; } void print(int now)///输出所有叶子节点 { if(node[now].l==node[now].r) printf("%lld ", node[now].sum); else { print(now<<1); print(now<<1^1); } } mint getsum(int x, int y)///表示求树从x到y结点最短路径上所有节点的值之和 { mint ans=0; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y);///把x点改为所在链顶端的深度更深的那个点 ans+=query(id[top[x]], id[x], 1);///一条链一条链的求和 x=fa[top[x]];///往高处跑 } if(dep[x]>dep[y]) swap(x, y); return ans+query(id[x], id[y], 1); } void updrag(int x, int y, mint k)///同上写法///表示将树从x到y结点最短路径上所有节点的值都加上k { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); update(id[top[x]], id[x], k, 1); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x, y); update(id[x], id[y], k, 1); } mint qson(int x)///表示求以x为根节点的子树内所有节点值之和 { ret=0; query(id[x], id[x]+siz[x]-1, 1);///他有siz[x]-1个子节点; return ret; } void updson(int x, int k)///表示将以x为根节点的子树内所有节点值都加上k { update(id[x], id[x]+siz[x]-1, k, 1); } }tree; void init() { Q(head, -1); Q(son, 0); sz=1; cnt=0; } void DFS(int now, int DEP, int F) { fa[now]=F; dep[now]=DEP; siz[now]=1; int key=-1; for(int i=head[now]; ~i; i=E[i].next) { if(E[i].to==F) continue; DFS(E[i].to, DEP+1, now); siz[now]+=siz[E[i].to]; if(siz[E[i].to]>key) son[now]=E[i].to, key=siz[E[i].to]; } } void DFS_(mint now, mint tp) { id[now]=++cnt; self[cnt]=sav[now];///这个点是build线段树用的 top[now]=tp;///按序将边加入线段树 if(!son[now]) return ; DFS_(son[now], tp);///重儿子的top[]从重链顶端继承 for(int i=head[now]; ~i; i=E[i].next) { if(E[i].to==son[now]||E[i].to==fa[now]) continue; DFS_(E[i].to, E[i].to);///轻儿子top[]为自身 } } int main() { mint m, r; while(~scanf("%d%d%d", &n, &m, &r)) { init(); for(int i=1; i<=n; i++) read(sav[i]); while(m--) { int a, b; read(a), read(b); insert_E(a, b); insert_E(b, a); } DFS(1, 1, 0); DFS_(1, 1); tree.build(1, n, 1); while(r--) { char op[33]; int x, y, z; scanf("%s", op); read(x); if(op[0]==‘I‘) read(y), read(z), tree.updrag(x, y, z); else if(op[0]==‘D‘) read(y), read(z), tree.updrag(x, y, -z); else printf("%d\n", tree.getsum(x, x)); } } return 0; }
#include<stdio.h> #include<string.h> #include<algorithm> #define Q(A, B) memset(A, B, sizeof(A)) using namespace std; const int N=50005; int fa[N], siz[N], dep[N], son[N]; int id[N], top[N], self[N], cnt; int sz, head[N]; int sav[N]; int n; void read(int &x) { int f=1;x=0;char s=getchar(); while(s<‘0‘|s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} x*=f; } struct Ed { int to, next; }E[N*2]; void insert_E(int u, int v) { E[sz].to=v; E[sz].next=head[u]; head[u]=sz++; } struct SZSZ_tree { int sum[N]; void init() { Q(sum, 0); } int lowbit(int x) { return x&(-x); } void update(int i, int v) { while(i<=n) { sum[i]+=v; i+=lowbit(i); } } int ALL(int i) { int res=0; while(i>0) { res+=sum[i]; i-=lowbit(i); } return res; } void updrag(int x, int y, int k)///同上写法///表示将树从x到y结点最短路径上所有节点的值都加上k { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); update(id[top[x]], k); update(id[x]+1, -k); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x, y); update(id[x], k); update(id[y]+1, -k); } }tree; void init() { Q(head, -1); Q(son, 0); tree.init(); sz=1; cnt=0; } void DFS(int now, int DEP, int F) { fa[now]=F; dep[now]=DEP; siz[now]=1; int key=-1; for(int i=head[now]; ~i; i=E[i].next) { if(E[i].to==F) continue; DFS(E[i].to, DEP+1, now); siz[now]+=siz[E[i].to]; if(siz[E[i].to]>key) son[now]=E[i].to, key=siz[E[i].to]; } } void DFS_(int now, int tp) { id[now]=++cnt; self[cnt]=sav[now];///这个点是build线段树用的 top[now]=tp;///按序将边加入线段树 if(!son[now]) return ; DFS_(son[now], tp);///重儿子的top[]从重链顶端继承 for(int i=head[now]; ~i; i=E[i].next) { if(E[i].to==son[now]||E[i].to==fa[now]) continue; DFS_(E[i].to, E[i].to);///轻儿子top[]为自身 } } int main() { int m, r; while(~scanf("%d%d%d", &n, &m, &r)) { init(); for(int i=1; i<=n; i++) read(sav[i]), tree.sum[i]=0; while(m--) { int a, b; read(a), read(b); insert_E(a, b); insert_E(b, a); } DFS(1, 1, 0); DFS_(1, 1); while(r--) { char op[33]; int x, y, z; scanf("%s", op); read(x); if(op[0]==‘I‘) read(y), read(z), tree.updrag(x, y, z); else if(op[0]==‘D‘) read(y), read(z), tree.updrag(x, y, -z); else printf("%d\n", tree.ALL(id[x])+sav[x]); } } return 0; }
以上是关于Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组的主要内容,如果未能解决你的问题,请参考以下文章
HDU 3966 Aragorn's Story(树链剖分)
HDU-3966 Aragorn's Story(树链剖分+线段树)