hdu 3966(树链剖分+线段树区间更新)
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 }
分割线:2019.5.10
省赛倒计时2天;
重新温习了一下树链剖分,改了改代码风格:
1 #pragma comment(linker,"/STACK:1024000000,1024000000")///手动扩栈 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define ls(x) (x<<1) 5 #define rs(x) (x<<1|1) 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 const int maxn=5e4+50; 8 9 int n,m,q;///n个点 ,m条边(m=n-1),q次询问 10 int a[maxn];///a[i]:初始i营地有a[i]个士兵 11 int num; 12 int head[maxn]; 13 struct Edge 14 { 15 int to; 16 int next; 17 }G[maxn<<1]; 18 void addEdge(int u,int v) 19 { 20 G[num]=Edge{v,head[u]}; 21 head[u]=num++; 22 } 23 int fa[maxn]; 24 int tid[maxn]; 25 int rid[maxn]; 26 int siz[maxn]; 27 int son[maxn]; 28 int top[maxn]; 29 int dep[maxn]; 30 struct Seg 31 { 32 int l,r; 33 int val; 34 int lazy; 35 int mid(){return l+((r-l)>>1);} 36 int len(){return r-l+1;}; 37 }seg[maxn<<2]; 38 39 void pushDown(int pos) 40 { 41 int &lazy=seg[pos].lazy; 42 if(lazy) 43 { 44 seg[ls(pos)].lazy += lazy; 45 seg[rs(pos)].lazy += lazy; 46 } 47 lazy=0; 48 } 49 void buildSegTree(int l,int r,int pos) 50 { 51 seg[pos].l=l; 52 seg[pos].r=r; 53 seg[pos].lazy=0; 54 seg[pos].val=0; 55 if(l == r) 56 { 57 seg[pos].val=a[rid[l]];///l点在树中对应的编号rid[l] 58 return ; 59 } 60 int mid=l+((r-l)>>1); 61 buildSegTree(l,mid,ls(pos)); 62 buildSegTree(mid+1,r,rs(pos)); 63 } 64 int Query(int l,int pos) 65 { 66 if(seg[pos].l == seg[pos].r) 67 return seg[pos].val+seg[pos].lazy; 68 69 pushDown(pos); 70 71 int mid=seg[pos].mid(); 72 if(l <= mid) 73 return Query(l,ls(pos)); 74 else 75 return Query(l,rs(pos)); 76 } 77 void Update(int l,int r,int pos,int val) 78 { 79 if(seg[pos].l == l && seg[pos].r == r) 80 { 81 seg[pos].lazy += val; 82 return ; 83 } 84 pushDown(pos); 85 86 int mid=seg[pos].mid(); 87 if(r <= mid) 88 Update(l,r,ls(pos),val); 89 else if(l > mid) 90 Update(l,r,rs(pos),val); 91 else 92 { 93 Update(l,mid,ls(pos),val); 94 Update(mid+1,r,rs(pos),val); 95 } 96 } 97 void Find(int u,int v,int val) 98 { 99 while(top[u] != top[v])///u,v不在同一条重链上 100 { 101 if(dep[top[u]] > dep[top[v]]) 102 swap(u,v); 103 104 Update(tid[top[v]],tid[v],1,val);///让u,v一步一步靠到同一条重链上 105 v=fa[top[v]]; 106 } 107 ///return 语句根据题意而定 108 ///再此题中,u==v时就是单点更新 109 // if(u == v) 110 // return ; 111 if(dep[u] > dep[v]) 112 swap(u,v); 113 ///这次不是tid[son[u]],因为上次是边权存在了儿子节点里 114 Update(tid[u],tid[v],1,val); 115 } 116 void DFS1(int u,int f,int depth) 117 { 118 fa[u]=f; 119 siz[u]=1; 120 dep[u]=depth; 121 for(int i=head[u];~i;i=G[i].next) 122 { 123 int v=G[i].to; 124 if(v == f) 125 continue; 126 127 DFS1(v,u,depth+1); 128 129 siz[u] += siz[v]; 130 if(son[u] == -1 || siz[v] > siz[son[u]]) 131 son[u]=v; 132 } 133 } 134 void DFS2(int u,int anc,int &k) 135 { 136 tid[u]=++k; 137 rid[k]=u; 138 top[u]=anc; 139 if(son[u] == -1) 140 return ; 141 DFS2(son[u],anc,k); 142 143 for(int i=head[u];~i;i=G[i].next) 144 { 145 int v=G[i].to; 146 if(v != fa[u] && v != son[u]) 147 DFS2(v,v,k); 148 } 149 } 150 void Solve() 151 { 152 DFS1(1,0,0); 153 int k=0; 154 DFS2(1,1,k); 155 buildSegTree(1,k,1); 156 157 char order[10]; 158 while(q--) 159 { 160 scanf("%s",order); 161 if(order[0] == 'Q') 162 { 163 int u; 164 scanf("%d",&u); 165 printf("%d\n",Query(tid[u],1));///单点查询,查询u营地当前的人数 166 } 167 else 168 { 169 int u,v,val; 170 scanf("%d%d%d",&u,&v,&val);///区间更新,更新营地[u,v]人数 +val 171 if(order[0] == 'D') 172 val=-val;///人数减少 173 Find(u,v,val); 174 } 175 } 176 } 177 void Init() 178 { 179 num=0; 180 mem(head,-1); 181 mem(son,-1); 182 } 183 int main() 184 { 185 while(~scanf("%d%d%d",&n,&m,&q)) 186 { 187 Init(); 188 for(int i=1;i <= n;++i) 189 scanf("%d",a+i); 190 for(int i=1;i <= m;++i) 191 { 192 int u,v; 193 scanf("%d%d",&u,&v); 194 addEdge(u,v); 195 addEdge(v,u); 196 } 197 Solve(); 198 } 199 return 0; 200 }