https://www.cnblogs.com/violet-acmer/p/9711441.html
学习资料:
[1]线段树区间更新:https://blog.csdn.net/zhhe0101/article/details/53871453
https://yq.aliyun.com/articles/252586
[2]树链剖分:http://blog.sina.com.cn/s/blog_7a1746820100wp67.html
https://wenku.baidu.com/view/7548d8706ad97f192279168884868762caaebbfc.html?from=search
题意:
敌军有N个营地,这N个营地通过M条边连接;
每个营地有且仅有一条边连接(意味着M=N-1,就是一颗含有N个节点的树)
要求支持两种操作:
1营地u与营地v以及其之间的所有营地增加或减少ai个士兵。
2询问营地u当前含有的士兵个数
题解:
树链剖分模板题。
实质上树链剖分进行了点对点的一次映射,保证了重链上的点在线段树上的位置是连续的。
树链剖分的两个性质(转):
性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];
性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。
保证了一个区间的时间复杂度是log2(n)。
要分清3种标号含义(易混) :树中节点标号,树中节点对应线段树中位置标号,线段树中区间标号。
树链剖分相关数组意义 :
siz[i] : 以i为根的子树的大小
fa[i] : i节点的父亲
depth[i] : i节点的深度
son[i] : i节点的重儿子(所有儿子中size最大的)
tid[i] : i节点在线段树中对应的位置
top[i] : i节点所在重链的顶端节点,若为轻链,则为自身。
rid[i] : 线段树中所对应树中节点(作用和tid[ ] 正好相反)。
AC代码:
摘抄自大佬博客:
分析:典型的树链剖分题目,先进行剖分,然后用线段树去维护即可,注意HDU的OJ采用Windows系统,容易爆栈,所以在代码前面加上:
#pragma comment(linker, "/STACK:1024000000,1024000000")进行手动扩栈。
(但不加也可以AC)
1 //#pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 #define ls(x)((x)<<1) 7 #define rs(x)((x)<<1 | 1) 8 const int maxn=5e4+10; 9 10 int A[maxn]; 11 //========链式前向星======== 12 struct Node1 13 { 14 int to; 15 int next; 16 }edge[maxn<<1]; 17 int head[maxn]; 18 int cnt; 19 void addEdge(int u,int v) 20 { 21 edge[cnt].to=v; 22 edge[cnt].next=head[u]; 23 head[u]=cnt++; 24 } 25 //========================== 26 //=========树链剖分========= 27 int fa[maxn]; 28 int son[maxn]; 29 int tid[maxn]; 30 int rid[maxn]; 31 int siz[maxn]; 32 int top[maxn]; 33 int depth[maxn]; 34 int label; 35 36 void dfs1(int u,int f,int d) 37 { 38 fa[u]=f; 39 siz[u]=1; 40 depth[u]=d; 41 for(int i=head[u];~i;i=edge[i].next) 42 { 43 int to=edge[i].to; 44 if(to != f) 45 { 46 dfs1(to,u,d+1); 47 siz[u] += siz[to]; 48 if(son[u] == -1 || siz[to] > siz[son[u]]) 49 son[u]=to; 50 } 51 } 52 } 53 void dfs2(int u,int newTop) 54 { 55 top[u]=newTop; 56 tid[u]=++label; 57 rid[tid[u]]=u; 58 if(son[u] == -1) 59 return ; 60 dfs2(son[u],newTop); 61 for(int i=head[u];~i;i=edge[i].next) 62 { 63 int to=edge[i].to; 64 if(to != son[u] && to != fa[u]) 65 dfs2(to,to); 66 } 67 } 68 //========================== 69 //==========线段树========== 70 struct Node2 71 { 72 int l,r; 73 int val; 74 int lazy; 75 int mid(){ 76 return l+((r-l)>>1); 77 } 78 }segTree[maxn<<2]; 79 void buildTree(int l,int r,int pos) 80 { 81 segTree[pos].l=l,segTree[pos].r=r; 82 segTree[pos].lazy=0; 83 if(l == r) 84 { 85 segTree[pos].val=A[rid[l]]; 86 return ; 87 } 88 int mid=l+((r-l)>>1); 89 buildTree(l,mid,ls(pos)); 90 buildTree(mid+1,r,rs(pos)); 91 } 92 void pushDown(int pos) 93 { 94 95 if(segTree[pos].lazy != 0) 96 { 97 segTree[ls(pos)].lazy += segTree[pos].lazy; 98 segTree[rs(pos)].lazy += segTree[pos].lazy; 99 100 //segTree[ls(pos)].val += segTree[pos].lazy; 101 //segTree[rs(pos)].val += segTree[pos].lazy; 102 103 segTree[pos].lazy=0; 104 } 105 } 106 void update(int a,int b,int val,int pos) 107 { 108 if(a <= segTree[pos].l && b >= segTree[pos].r) 109 { 110 segTree[pos].lazy += val; 111 //segTree[pos].val += val; 112 return ; 113 } 114 pushDown(pos); 115 116 int mid=segTree[pos].mid(); 117 if(b <= mid) 118 update(a,b,val,ls(pos)); 119 else if(a > mid) 120 update(a,b,val,rs(pos)); 121 else 122 { 123 update(a,mid,val,ls(pos)); 124 update(mid+1,b,val,rs(pos)); 125 } 126 } 127 int query(int k,int pos) 128 { 129 if(segTree[pos].l == segTree[pos].r) 130 return segTree[pos].val+segTree[pos].lazy; 131 132 pushDown(pos); 133 int mid=segTree[pos].mid(); 134 135 if(k <= mid) 136 return query(k,ls(pos)); 137 else 138 return query(k,rs(pos)); 139 } 140 //========================== 141 void Find(int a,int b,int val) 142 { 143 while(top[a] != top[b]) 144 { 145 if(depth[top[a]] > depth[top[b]]) 146 { 147 update(tid[top[a]],tid[a],val,1); 148 a=fa[top[a]]; 149 } 150 else 151 { 152 update(tid[top[b]],tid[b],val,1); 153 b=fa[top[b]]; 154 } 155 } 156 if(tid[a] > tid[b]) 157 swap(a,b); 158 update(tid[a],tid[b],val,1); 159 } 160 161 void init() 162 { 163 cnt=0; 164 memset(head,-1,sizeof(head)); 165 label=0; 166 memset(son,-1,sizeof(son)); 167 } 168 int main() 169 { 170 int n,m,q; 171 while(~scanf("%d%d%d",&n,&m,&q)) 172 { 173 init(); 174 for(int i=1;i <= n;++i) 175 scanf("%d",A+i); 176 for(int i=1;i <= m;++i) 177 { 178 int u,v; 179 scanf("%d%d",&u,&v); 180 addEdge(u,v); 181 addEdge(v,u); 182 } 183 dfs1(1,1,0); 184 dfs2(1,1); 185 buildTree(1,label,1); 186 char op[3]; 187 for(int i=1;i <= q;++i) 188 { 189 scanf("%s",op); 190 if(op[0] == 'Q') 191 { 192 int c; 193 scanf("%d",&c); 194 printf("%d\n",query(tid[c],1)); 195 } 196 else 197 { 198 int c1,c2,k; 199 scanf("%d%d%d",&c1,&c2,&k); 200 if(op[0] == 'D') 201 k = -k; 202 Find(c1,c2,k); 203 } 204 } 205 } 206 return 0; 207 }