标签:
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\n",query(w[x],1,n,1)); 144 } 145 } 146 } 147 }
标签:
原文地址:http://www.cnblogs.com/rpSebastian/p/5722270.html