BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)
Posted sigongzi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)相关的知识,希望对你有一定的参考价值。
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14982 Solved: 6081
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
1
2
2
10
6
5
6
5
16
——————————————题解
毕竟是模板……
所谓的线段树维护链,就是建很多个线段树,节点一个挨着一个省空间
代码量……真是……
1 //大家吼,我要砍树了 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <queue> 7 #include <set> 8 #include <vector> 9 #include <string.h> 10 #define siji(i,x,y) for(int i=(x);i<=(y);++i) 11 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j) 12 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i) 13 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j) 14 #define inf 0x7fffffff 15 //#define ivorysi 16 #define mo 97797977 17 #define hash 974711 18 #define base 47 19 #define MAXN 30005 20 #define fi first 21 #define se second 22 #define pii pair<int,int> 23 using namespace std; 24 //树的存储 25 struct node { 26 int to,next; 27 }edge[MAXN*3]; 28 int head[MAXN],sumedge,n,q; 29 int val[MAXN];//点值 30 31 void add(int u,int v) { 32 edge[++sumedge].to=v; 33 edge[sumedge].next=head[u]; 34 head[u]=sumedge; 35 } 36 //线段树部分变量定义 37 struct data { 38 int l,r,//边界 39 lson,//左儿子(因为不能直接位运算要节省空间) 40 rson,//右儿子(因为不能直接位运算要节省空间) 41 sum,//区间总和 42 maxp,//区间最大值 43 fa;//单点更新优化 44 data() { 45 l=0,r=0,lson=0,rson=0,sum=0,maxp=-inf,fa=0; 46 } 47 }tree[MAXN*10]; 48 int treecnt;//树点个数 49 int w[MAXN];//单点更新优化 50 51 //剖分部分变量定义 52 int fa[MAXN],//父亲 53 dep[MAXN],//深度 54 size[MAXN],//子树大小 55 son[MAXN],//重儿子 56 rank[MAXN],//在链中的位置 57 belong[MAXN],//属于哪条链 58 top[MAXN],//这个点所在链的深度最小的点 59 linkcnt,//链数 60 lroot[MAXN];//每条链的树根 61 62 //剖分部分 63 void dfs1(int u) {//size,fa,son,dep 64 size[u]=1; 65 for(int i=head[u];i;i=edge[i].next) { 66 int v=edge[i].to; 67 if(v!=fa[u]) { 68 fa[v]=u; 69 dep[v]=dep[u]+1; 70 dfs1(v); 71 size[u]+=size[v]; 72 if(size[v]>size[son[u]]) son[u]=v; 73 } 74 } 75 } 76 void build(int p,int l,int r); 77 vector<int> line; 78 void dfs2(int u) {//belong,top,rank 79 if(!belong[u]) { 80 belong[u]=++linkcnt; 81 top[linkcnt]=u; 82 rank[u]=1; 83 84 } 85 line.push_back(u); 86 if(!son[u]) { 87 lroot[belong[u]]=++treecnt; 88 build(treecnt,1,line.size()); 89 line.clear(); 90 return; 91 } 92 belong[son[u]]=belong[u]; 93 rank[son[u]]=rank[u]+1; 94 dfs2(son[u]); 95 for(int i=head[u];i;i=edge[i].next) { 96 int v=edge[i].to; 97 if(v!=son[u] && v!=fa[u]) 98 dfs2(v); 99 } 100 101 } 102 //剖分部分结束 103 //———————————————————————————— 104 //线段树部分 105 void build(int p,int l,int r) { 106 tree[p].l=l; 107 tree[p].r=r; 108 if(l==r) { 109 tree[p].sum=val[line[l-1]]; 110 tree[p].maxp=val[line[l-1]]; 111 w[line[l-1]]=p; 112 return; 113 } 114 int mid=(l+r)>>1; 115 tree[p].lson=++treecnt; 116 tree[treecnt].fa=p; 117 build(treecnt,l,mid); 118 int t1=tree[tree[p].lson].maxp; 119 int t3=tree[tree[p].lson].sum; 120 tree[p].rson=++treecnt; 121 tree[treecnt].fa=p; 122 build(treecnt,mid+1,r); 123 int t2=tree[tree[p].rson].maxp; 124 int t4=tree[tree[p].rson].sum; 125 tree[p].sum+=t3+t4; 126 tree[p].maxp=max(t1,t2); 127 return; 128 } 129 void change(int u) { 130 tree[w[u]].sum=tree[w[u]].maxp=val[u]; 131 int z=tree[w[u]].fa; 132 while(z!=0) { 133 tree[z].sum=tree[tree[z].lson].sum+tree[tree[z].rson].sum; 134 tree[z].maxp=max(tree[tree[z].lson].maxp,tree[tree[z].rson].maxp); 135 z=tree[z].fa; 136 } 137 } 138 int treeqsum(int p,int l,int r) { 139 if(l <= tree[p].l && r >= tree[p].r) { 140 return tree[p].sum; 141 } 142 int mid=(tree[p].l+tree[p].r)>>1; 143 int t1=0,t2=0; 144 if(l <= mid) { 145 t1=treeqsum(tree[p].lson,l,r); 146 } 147 if(r > mid){ 148 t2=treeqsum(tree[p].rson,l,r); 149 } 150 return t1+t2; 151 } 152 int treeqmax(int p,int l,int r) { 153 if(l <= tree[p].l && r >= tree[p].r) { 154 return tree[p].maxp; 155 } 156 int mid=(tree[p].l+tree[p].r)>>1; 157 int t1=-inf,t2=-inf; 158 if(l <= mid) { 159 t1=treeqmax(tree[p].lson,l,r); 160 } 161 if(r > mid){ 162 t2=treeqmax(tree[p].rson,l,r); 163 } 164 return max(t1,t2); 165 } 166 //线段树部分结束 167 //—————————————————————————— 168 //解决问题部分 169 int qsum(int u,int v){ 170 int x=top[belong[u]],y=top[belong[v]],res=0; 171 while(belong[u]!=belong[v]) { 172 if(dep[x]>dep[y]){ 173 res+=treeqsum(lroot[belong[x]],tree[lroot[belong[x]]].l,rank[u]); 174 u=fa[x]; 175 } 176 else { 177 res+=treeqsum(lroot[belong[y]],tree[lroot[belong[y]]].l,rank[v]); 178 v=fa[y]; 179 } 180 x=top[belong[u]],y=top[belong[v]]; 181 } 182 x=max(rank[u],rank[v]); 183 y=rank[u]+rank[v]-x; 184 res+=treeqsum(lroot[belong[u]],y,x); 185 return res; 186 187 } 188 int qmax(int u,int v) { 189 int x=top[belong[u]],y=top[belong[v]],res=-inf; 190 while(belong[x]!=belong[y]) { 191 if(dep[x]>dep[y]){ 192 res=max(res,treeqmax(lroot[belong[x]],tree[lroot[belong[x]]].l,rank[u])); 193 u=fa[x]; 194 } 195 else { 196 res=max(res,treeqmax(lroot[belong[y]],tree[lroot[belong[y]]].l,rank[v])); 197 v=fa[y]; 198 } 199 x=top[belong[u]],y=top[belong[v]]; 200 } 201 x=max(rank[u],rank[v]); 202 y=rank[u]+rank[v]-x; 203 res=max(res,treeqmax(lroot[belong[u]],y,x)); 204 return res; 205 } 206 void prepare() { 207 int u,v; 208 scanf("%d",&n); 209 xiaosiji(i,1,n) { 210 scanf("%d %d",&u,&v); 211 add(u,v),add(v,u); 212 } 213 siji(i,1,n) { 214 scanf("%d",&val[i]); 215 } 216 scanf("%d",&q); 217 dfs1(1),dfs2(1); 218 } 219 void solve() { 220 prepare(); 221 char ord[10]; 222 siji(i,1,q) { 223 scanf("%s",ord); 224 if(ord[0]==‘C‘) { 225 int u; 226 scanf("%d",&u); 227 //之前写成scanf("%d%d",&u,&val[u]);应该是因为它获得的是原来的u,可能是个很大的野值 228 scanf("%d",&val[u]); 229 change(u); 230 } 231 else if(ord[1]==‘M‘) { 232 int u,v; 233 scanf("%d%d",&u,&v); 234 printf("%d\n",qmax(u,v)); 235 } 236 else { 237 int u,v; 238 scanf("%d%d",&u,&v); 239 printf("%d\n",qsum(u,v)); 240 } 241 } 242 } 243 int main(int argc, char const *argv[]) 244 { 245 #ifdef ivorysi 246 freopen("f1.in","r",stdin); 247 #endif 248 solve(); 249 }
以上是关于BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1036: [ZJOI2008]树的统计Count
bzoj 1036: [ZJOI2008]树的统计Count
BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]