BZOJ1036树的统计
Posted Beginner_llg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1036树的统计相关的知识,希望对你有一定的参考价值。
1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 18285 Solved: 7445
[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
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
2
10
6
5
6
5
16
题解:树链剖分模板题,不解释啦。
树链剖分详见大佬们的博客,介绍得很详细
http://hzwer.com/2543.html
http://www.cnblogs.com/ghostfly233/p/7168324.html
代码如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #define Max 30005 5 #define INF 0x7fffffff 6 using namespace std; 7 int n,m,cnt,v[Max],dep[Max],size[Max],fa[Max]; 8 int pos[Max],center[Max];//pos:节点标号 center:节点所在重链链头 9 vector<int> G[Max]; 10 struct node{int l,r,sum,maxn;}tree[3*Max]; 11 void init(){ 12 scanf("%d",&n); 13 for(int i=1;i<n;i++){ 14 int x,y; scanf("%d%d",&x,&y); 15 G[x].push_back(y); G[y].push_back(x); 16 } 17 for(int i=1;i<=n;i++) scanf("%d",&v[i]); 18 } 19 void dfs1(int x){//求出size、dep、fa 20 size[x]=1; 21 for(int i=0;i<G[x].size();i++){ 22 int to=G[x][i]; 23 if(to==fa[x]) continue; 24 dep[to]=dep[x]+1; fa[to]=x; dfs1(to); 25 size[x]+=size[to]; 26 } 27 } 28 void dfs2(int x,int chain){//求出pos、center 29 int k=0; 30 pos[x]=++cnt; center[x]=chain; 31 for(int i=0;i<G[x].size();i++){ 32 int to=G[x][i]; 33 if(dep[to]>dep[x]&&size[to]>size[k]) k=to;//找出重儿子 34 } 35 if(k==0) return; 36 dfs2(k,chain);//重儿子继承重链 37 for(int i=0;i<G[x].size();i++){ 38 int to=G[x][i]; 39 if(dep[to]>dep[x]&&k!=to) dfs2(to,to);//其余儿子分别重新开链 40 } 41 } 42 void build(int k,int l,int r){//建线段树 43 tree[k].l=l; tree[k].r=r; 44 if(l==r) return; 45 int mid=(l+r)>>1; 46 build(k<<1,l,mid); build(k<<1|1,mid+1,r); 47 } 48 void change(int k,int x,int add){//单点修改 49 int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1; 50 if(l==r){tree[k].sum=tree[k].maxn=add; return;} 51 if(x<=mid) change(k<<1,x,add); 52 else change(k<<1|1,x,add); 53 tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; 54 tree[k].maxn=max(tree[k<<1].maxn,tree[k<<1|1].maxn); 55 } 56 int querymaxn(int k,int x,int y){ 57 int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1; 58 if(l==x&&r==y) return tree[k].maxn; 59 if(y<=mid) return querymaxn(k<<1,x,y); 60 else if(x>mid) return querymaxn(k<<1|1,x,y); 61 else return max(querymaxn(k<<1,x,mid),querymaxn(k<<1|1,mid+1,y)); 62 } 63 int querysum(int k,int x,int y){ 64 int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1; 65 if(l==x&&r==y) return tree[k].sum; 66 if(y<=mid) return querysum(k<<1,x,y); 67 else if(x>mid) return querysum(k<<1|1,x,y); 68 else return querysum(k<<1,x,mid)+querysum(k<<1|1,mid+1,y); 69 } 70 int solvemaxn(int x,int y){ 71 int ret=-INF; 72 while(center[x]!=center[y]){//不在同一重链 73 if(dep[center[x]]<dep[center[y]]) swap(x,y); 74 ret=max(ret,querymaxn(1,pos[center[x]],pos[x])); 75 x=fa[center[x]];//较深节点向上走到fa[链头] ,并查询这段的maxn 76 } 77 if(pos[x]>pos[y]) swap(x,y);//走到同一重链后还要在查询两点间这一段 78 ret=max(ret,querymaxn(1,pos[x],pos[y])); 79 return ret; 80 } 81 int solvesum(int x,int y){ 82 int ret=0; 83 while(center[x]!=center[y]){ 84 if(dep[center[x]]<dep[center[y]]) swap(x,y); 85 ret+=querysum(1,pos[center[x]],pos[x]); 86 x=fa[center[x]]; 87 } 88 if(pos[x]>pos[y]) swap(x,y); 89 ret+=querysum(1,pos[x],pos[y]); 90 return ret; 91 } 92 void solve(){ 93 build(1,1,n); 94 for(int i=1;i<=n;i++) change(1,pos[i],v[i]); 95 scanf("%d",&m); 96 for(int i=1;i<=m;i++){ 97 int x,y; char ch[10]; 98 scanf("%s%d%d",ch,&x,&y); 99 if(ch[0]==\'C\') change(1,pos[x],y); 100 else if(ch[1]==\'M\') printf("%d\\n",solvemaxn(x,y)); 101 else printf("%d\\n",solvesum(x,y)); 102 } 103 } 104 int main() 105 { 106 init(); 107 dfs1(1); 108 dfs2(1,1); 109 solve(); 110 return 0; 111 }
以上是关于BZOJ1036树的统计的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)
BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)