HDU 3966 (树链剖分+线段树)

Problem Aragorn's Story (HDU 3966)

题目大意

  给定一颗树,有点权。

  要求支持两种操作,将一条路径上的所有点权值增加或减少ai,询问某点的权值。

解题分析

  树链剖分模板题。

  实质上树链剖分进行了点对点的一次映射,保证了重链上的点在线段树上的位置是连续的。

  树链剖分的两个性质(转):

    性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];

    性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。

  保证了一个区间的时间复杂度是log2(n)。

  要分清3种标号含义(易混) :树中节点标号,树中节点对应线段树中位置标号,线段树中区间标号。

  树链剖分相关数组意义 :

    size[i] :以i为根的子树的大小

    fa[i] :i节点的父亲

    dep[i] :i节点的深度

    son[i] :i节点的重儿子(所有儿子中size最大的)

    w[i] :i节点在线段树中对应的位置

    top[i] :i节点所在重链的顶端节点,若为轻链,则为自身。

    rank[i] :线段树中所对应树中节点。

参考程序

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <cmath>
  5 
  6 #define V 50008
  7 #define E 100008
  8 #define lson l,m,rt<<1
  9 #define rson m+1,r,rt<<1|1
 10 
 11 int n,m,Q;
 12 int a[V],size[V],dep[V],fa[V],top[V],w[V],son[V],rank[V];
 13 int sum[V << 2],lazy[V << 2];
 14 
 15 struct line{
 16     int u,v,nt;
 17 }eg[E];
 18 int lt[V],summ,cnt;
 19 
 20 void adt(int u,int v){
 21     eg[++summ].u=u; eg[summ].v=v; eg[summ].nt=lt[u]; lt[u]=summ;
 22 }
 23 
 24 void add(int u,int v){
 25     adt(u,v); adt(v,u);
 26 }
 27 
 28 void dfs1(int u){
 29     size[u]=1; son[u]=0;
 30     for (int i=lt[u];i;i=eg[i].nt){
 31         int v=eg[i].v;
 32         if (v!=fa[u]){
 33             fa[v]=u;
 34             dep[v]=dep[u]+1;
 35             dfs1(v);
 36             size[u]+=size[v];
 37             if (size[v]>size[son[u]]) son[u]=v;
 38         }
 39     }
 40 }
 41 
 42 void dfs2(int u,int tp,int x){
 43     top[u]=tp; w[u]=++cnt; rank[cnt]=u;
 44     if (son[u]) dfs2(son[u],tp,1);
 45     for (int i=lt[u];i;i=eg[i].nt){
 46         int v=eg[i].v;
 47         if (v==son[u] || v==fa[u]) continue;
 48         dfs2(v,v,2);
 49     }
 50 }
 51 
 52 void init(){
 53     memset(lt,0,sizeof(lt));
 54     summ=1; cnt=0;
 55     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 56     for (int i=1;i<=m;i++){
 57         int u,v;
 58         scanf("%d %d",&u,&v);
 59         add(u,v);
 60     }
 61     dep[1]=1; fa[1]=0; 
 62     dfs1(1);
 63     dfs2(1,1,1);
 64 }
 65 
 66 void pushup(int rt){
 67     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 68 }
 69 
 70 void pushdown(int rt,int m){
 71     if (lazy[rt]){
 72         lazy[rt<<1]+=lazy[rt];
 73         lazy[rt<<1|1]+=lazy[rt];
 74         sum[rt<<1]+=lazy[rt]*(m-m / 2);
 75         sum[rt<<1|1]+=lazy[rt]*(m / 2);
 76         lazy[rt]=0;
 77     }
 78 }
 79 
 80 void build(int l,int r,int rt){
 81     lazy[rt]=0;
 82     if (l==r){
 83         sum[rt]=a[rank[l]];
 84         return;
 85     }
 86     int m=(l+r)/2;
 87     build(lson);
 88     build(rson);
 89     pushup(rt);
 90 }
 91 
 92 void update(int L,int R,int val,int l,int r,int rt){
 93     if (L<=l && r<=R){
 94         sum[rt]+=val*(r-l+1);
 95         lazy[rt]+=val;
 96         return;
 97     }
 98     pushdown(rt,r-l+1);
 99     int m=(l+r)>>1;
100     if (L<=m) update(L,R,val,lson);
101     if (m< R) update(L,R,val,rson);
102     pushup(rt);
103 }
104 
105 int query(int x,int l,int r,int rt){
106     if (l==r){
107         return sum[rt];
108     }
109     pushdown(rt,r-l+1);
110     int m=(l+r)>>1;
111     if (x<=m) return query(x,lson);
112     if (m< x) return query(x,rson);
113 }
114 
115 void change(int x,int y,int val){
116     while (top[x]!=top[y]){
117         if (dep[top[x]]<dep[top[y]]) std::swap(x,y);
118         update(w[top[x]],w[x],val,1,n,1);
119         x=fa[top[x]];
120     }
121     if (dep[x]>dep[y]) std::swap(x,y);
122     update(w[x],w[y],val,1,n,1);
123 }
124 
125 int main(){
126     while (~scanf("%d %d %d",&n,&m,&Q)){
127         init();
128         build(1,n,1);
129         while (Q--){
130             char s[2];
131             int x,y,z;
132             scanf("%s",s);
133             if (s[0]=='I'){
134                 scanf("%d %d %d",&x,&y,&z);
135                 change(x,y,z);
136             }    
137             if (s[0]=='D'){
138                 scanf("%d %d %d",&x,&y,&z);
139                 change(x,y,-z);
140             }
141             if (s[0]=='Q'){
142                 scanf("%d",&x);
143                 printf("%d
",query(w[x],1,n,1));
144             }
145         }
146     }
147 }
View Code
原文地址:https://www.cnblogs.com/rpSebastian/p/5722270.html