hdu3966 树链剖分模板(点权,修改区间查询点)

  1 #pragma comment(linker, "/STACK:1024000000,1024000000")
  2 #include<stdio.h>
  3 #include<string.h>
  4 int now,cnt,n,a[50005];
  5 int next[100005],head[50005],point[100005];
  6 int num[50005],father[50005],son[50005],deep[50005];
  7 int top[50005],tree[50005],pre[50005];
  8 int seg[200005],setv[200005];
  9 void add(int x,int y)
 10 {
 11     next[++now]=head[x];
 12     head[x]=now;
 13     point[now]=y;
 14 }
 15 void dfs1(int u)
 16 {
 17     num[u]=1; //节点儿子数(包括自己)
 18     for (int i=head[u];i!=-1;i=next[i])
 19     {
 20         int v=point[i];
 21         if (v!=father[u]){
 22             father[v]=u; //父亲节点
 23             deep[v]=deep[u]+1;//节点深度
 24             dfs1(v);
 25             num[u]+=num[v];//讲v dfs完之后再加上num
 26             if (son[u]==-1||num[v]>num[son[u]]) son[u]=v; //儿子节点中num最多的为重链,son为重儿子
 27         }
 28     }
 29 }
 30 void dfs2(int u,int lead)
 31 {
 32     top[u]=lead; //进来的点都是重链上的点,top为该点的重链根
 33     tree[u]=++cnt;//重链上的点映射到线段树上编号
 34     pre[cnt]=u;//线段树上的点到原树上的点编号,为了建树
 35     if (son[u]==-1) return;
 36     dfs2(son[u],lead); //先把该条树上重链走完,再线段树上才能是连续的
 37     for (int i=head[u];i!=-1;i=next[i])
 38     {
 39         int v=point[i];//走一步轻链
 40         if (father[u]!=v&&son[u]!=v) dfs2(v,v);
 41     }
 42 }
 43 
 44 void build(int o,int l,int r)
 45 {
 46     seg[o]=0; setv[o]=0;
 47     if (l==r) {
 48         seg[o]=a[pre[l]];
 49         return;
 50     }
 51     int mid=l+(r-l)/2;
 52     build(o*2,l,mid);
 53     build(o*2+1,mid+1,r);
 54 }
 55 void update(int o,int l,int r,int y1,int y2,int d)
 56 {
 57     if (y1<=l&&y2>=r)
 58     {
 59         setv[o]+=d;
 60         return;
 61     }
 62     if (setv[o]!=0) //pushdown
 63     {
 64         setv[o*2]+=setv[o];
 65         setv[o*2+1]+=setv[o];
 66         setv[o]=0;
 67     }
 68     int mid=l+(r-l)/2;
 69     if (y1<=mid) update(o*2,l,mid,y1,y2,d);
 70     if (y2>mid) update(o*2+1,mid+1,r,y1,y2,d);
 71 }
 72 int query(int o,int l,int r,int y)
 73 {
 74     if (l==r) return seg[o]+setv[o];
 75     if (setv[o]!=0) //pushdown
 76     {
 77         setv[o*2]+=setv[o];
 78         setv[o*2+1]+=setv[o];
 79         setv[o]=0;
 80     }
 81     int mid=l+(r-l)/2;
 82     if (y<=mid) return query(o*2,l,mid,y);
 83     return query(o*2+1,mid+1,r,y);
 84 }
 85 
 86 void change(int l,int r,int d)//连接树与线段树核心
 87 {
 88     int temp;
 89     while (top[l]!=top[r]) //直到在一条重链上
 90     {
 91         if (deep[top[l]]<deep[top[r]]) {temp=l; l=r; r=temp; }//先处理更深重链
 92         update(1,1,n,tree[top[l]],tree[l],d);//核心!
 93         l=father[top[l]];
 94     }
 95     if (deep[l]>deep[r]) {temp=l; l=r; r=temp; }
 96     update(1,1,n,tree[l],tree[r],d);
 97 }
 98 int main()
 99 {
100     int m,q,i,x,y,d;
101     char s[5];
102     while (~scanf("%d%d%d",&n,&m,&q))
103     {
104         now=0; cnt=0;
105         deep[1]=1; father[1]=1;
106         memset(son,-1,sizeof(son));
107         memset(head,-1,sizeof(head));
108         for (i=1;i<=n;i++) scanf("%d",&a[i]);
109         for (i=1;i<=m;i++)
110         {
111             scanf("%d%d",&x,&y);
112             add(x,y); add(y,x);
113         }
114         dfs1(1); dfs2(1,1);
115         build(1,1,n);
116         for (i=1;i<=q;i++)
117         {
118             scanf("%s",&s);
119             if (s[0]=='Q') {
120                 scanf("%d",&x);
121                 printf("%d\n",query(1,1,n,tree[x]));
122             }
123             else{
124                 scanf("%d%d%d",&x,&y,&d);
125                 if (s[0]=='D') d=-d;
126                 change(x,y,d);
127             }
128         }
129     }
130     return 0;
131 }

http://acm.hdu.edu.cn/showproblem.php?pid=3966

posted on 2014-10-01 15:02  xiao_xin  阅读(172)  评论(0编辑  收藏  举报

导航