树链刨分 HDU 3966

Posted HelloWorld!--By-MJY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链刨分 HDU 3966相关的知识,希望对你有一定的参考价值。

树 n个点 m条边(其实就是n-1) q个询问

a1 a2 a3 ...

这些节点开始的人

I  a b c   a->b  这条链上的都加c

D    ...                             减

q  a  查询节点a上的人

具体看代码上的注释

#include<stdio.h>
#include<string.h>
#include<algorithm>

using namespace std;
#define MAXN 50010
struct edge
{
    int to,w,next;
}x[2*MAXN];
int head[MAXN];
int num[MAXN],siz[MAXN],     top[MAXN], son[MAXN],dep[MAXN],tid[MAXN];
int _tid[MAXN],father[MAXN];
// 权    包括这个点子树节点数 树链的头   重孩子   深度    树链中下标
/ 根据线段树的l找到这个点  父亲
int cnt,n,m,q,tim; void add(int u,int v) //建边   { x[cnt].to=v; x[cnt].next=head[u]; head[u]=cnt++; } void init(int n) { cnt=0; tim=0; memset(head,-1,sizeof(head)); memset(son,0,sizeof(son)); } void dfs1(int u,int fa) { siz[u]=1;//包括这个点的子树的节点数 father[u]=fa; dep[u]=dep[fa]+1; for(int i=head[u];i!=-1;i=x[i].next) { int v=x[i].to; if(v==fa) continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[son[u]] < siz[v])//找到重孩子 son[u] = v; } } void dfs2(int u,int tp)// { tid[u]=++tim;// 线段树中的l r  _tid[tim]=u;// 反过来 top[u]=tp; //链的头 if(son[u]!=0)// 在一调链上 就在线段树的连续的一部分 dfs2(son[u],tp); for(int i=head[u];i!=-1;i=x[i].next) { int v=x[i].to; if(v!=father[u]&&v!=son[u])  //既不是父亲也不是重孩子  重新刨分  dfs2(v,v); } } struct node { int l,r,val,lazy; }z[MAXN<<3]; void update(int l,int r,int a1,int b1,int v,int a); void change(int x,int y,int val) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); update(1,n,tid[top[x]],tid[x],val,1);//链头到 这个节点更新 x = father[top[x]]; } if(dep[x] > dep[y]) swap(x,y); update(1,n,tid[x],tid[y],val,1); //最后 } void build(int l,int r,int a) { z[a].l=l; z[a].r=r; z[a].val=z[a].lazy=0; if(l==r) { z[a].val=num[_tid[l]]; return ; } int mid=(l+r)>>1; build(l,mid,a<<1); build(mid+1,r,a<<1|1); } void push_down(int a) { if(z[a].lazy) { z[a<<1].val+=z[a].lazy; z[a<<1|1].val+=z[a].lazy; z[a<<1].lazy+=z[a].lazy; z[a<<1|1].lazy+=z[a].lazy; z[a].lazy=0; } } void update(int l,int r,int a1,int b1,int v,int a) { if(a1<=l&&r<=b1) { z[a].val+=v; z[a].lazy+=v; return ; } push_down(a); int mid=(l+r)>>1; if(a1<=mid) update(l,mid,a1,b1,v,a<<1); if(b1>mid) update(mid+1,r,a1,b1,v,a<<1|1); } int Ques(int l,int r,int x,int a) { push_down(a); if(l==r&&l==x) return z[a].val; int mid=(l+r)>>1; if(x<=mid) return Ques(l,mid,x,a<<1); else return Ques(mid+1,r,x,a<<1|1); } int main() { while(scanf("%d%d%d",&n,&m,&q)!=EOF) { init(n); for(int i=1;i<=n;i++) scanf("%d",&num[i]); while(m--) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs1(1,0);// 2个深搜 dfs2(1,1); build(1,n,1);//建树 while(q--) { char s[5]; scanf("%s",s); if(s[0]==Q) { int a; scanf("%d",&a); printf("%d\n",Ques(1,n,tid[a],1)); } else { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(s[0]==I) change(a,b,c); else change(a,b,-c); } } } return 0; }

 

以上是关于树链刨分 HDU 3966的主要内容,如果未能解决你的问题,请参考以下文章

hdu3966(树链剖分)

HDU 3966 Aragorn&#39;s Story(树链剖分)

hdu3966 树链剖分+线段树 裸题

hdu3966(树链剖分+线段树)

HDU - 3966 Aragorn's Story(树链剖分入门+线段树)

HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问