BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

Posted sigongzi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)相关的知识,希望对你有一定的参考价值。

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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

4
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

4
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 [树链剖分]

bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

[Bzoj1036][ZJOI2008]树的统计Count

bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板