洛谷P2590 [ZJOI2008]树的统计

题目:https://www.luogu.org/problemnew/show/2590

题目描述

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。

我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

注意:从点u到点v的路径上的节点包括u和v本身

输入输出格式

输入格式:

 

输入文件的第一行为一个整数n,表示节点的个数。

接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

接下来一行n个整数,第i个整数wi表示节点i的权值。

接下来1行,为一个整数q,表示操作的总数。

接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

 

输出格式:

 

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

 

输入输出样例

输入样例#1: 
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: 
4
1
2
2
10
6
5
6
5
16

说明

对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

 

解析

这个。。。没有啥可解析的吧。。。。。。

树剖版题。

我终于写对了一个树剖啦。。。。。。

(我还是太菜了)

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<vector>
  7 using namespace std;
  8 const int N=30500;
  9 const int M=70500;
 10 const int inf=233333333;
 11 
 12 vector<int> edge[N];
 13 
 14 int n,m,ra,rb;
 15 int val[N];
 16 int fa[N],tot[N],depth[N];
 17 int top[N],num[N],numx[N],t;
 18 
 19 struct node{
 20     int maxv,sum;
 21 };
 22 node tree[M];
 23 
 24 void addedge(int x,int y){
 25     edge[x].push_back(y);
 26     edge[y].push_back(x);
 27 }
 28 
 29 void dfsa(int x){
 30     depth[x]=depth[fa[x]]+1;
 31     tot[x]=1;
 32     for (int i=0;i<edge[x].size();++i){
 33         int nxt=edge[x][i];
 34         if (nxt!=fa[x]){
 35             fa[nxt]=x;
 36             dfsa(nxt);
 37             tot[x]+=tot[nxt];
 38         }
 39     }
 40 }
 41 
 42 void dfsb(int x){
 43     ++t;
 44     num[x]=t;
 45     numx[t]=x;
 46     if (!top[x]) top[x]=x;
 47     int big=0;
 48     for (int i=0;i<edge[x].size();++i){
 49         int nxt=edge[x][i];
 50         if (nxt!=fa[x]&&tot[nxt]>tot[big])
 51           big=nxt; 
 52     }
 53     if (big){
 54         top[big]=top[x];
 55         dfsb(big);
 56     }
 57     for (int i=0;i<edge[x].size();++i){
 58         int nxt=edge[x][i];
 59         if (nxt!=fa[x]&&nxt!=big)
 60           dfsb(nxt);
 61     }
 62 }
 63 
 64 void maketree(int o,int l,int r){
 65     if (l==r){
 66         tree[o].maxv=val[numx[l]];
 67         tree[o].sum=val[numx[l]];
 68         return;
 69     }
 70     int ls=o<<1;
 71     int rs=ls|1;
 72     int mid=(l+r)>>1;
 73     maketree(ls,l,mid);
 74     maketree(rs,mid+1,r);
 75     tree[o].sum=tree[ls].sum+tree[rs].sum;
 76     tree[o].maxv=max(tree[ls].maxv,tree[rs].maxv);
 77 }
 78 
 79 void change(int o,int l,int r,int a,int v){
 80     if (l==r){
 81         tree[o].maxv=tree[o].sum=v;
 82         return;
 83     }
 84     int mid=(l+r)>>1;
 85     int ls=o<<1;
 86     int rs=ls|1;
 87     if (a<=mid) change(ls,l,mid,a,v);
 88     else change(rs,mid+1,r,a,v);
 89     tree[o].maxv=max(tree[ls].maxv,tree[rs].maxv);
 90     tree[o].sum=tree[ls].sum+tree[rs].sum;
 91 }
 92 
 93 int getsum(int o,int l,int r,int ql,int qr){
 94     if (ql<=l&&qr>=r) return tree[o].sum;
 95     int mid=(l+r)>>1;
 96     int ls=o<<1;
 97     int rs=ls|1;
 98     int ans=0;
 99     if (ql<=mid) ans+=getsum(ls,l,mid,ql,qr);
100     if (qr>mid) ans+=getsum(rs,mid+1,r,ql,qr);
101     return ans;
102 }
103 int getmax(int o,int l,int r,int ql,int qr){
104     if (ql<=l&&qr>=r) return tree[o].maxv;
105     int mid=(l+r)>>1;
106     int ls=o<<1;
107     int rs=ls|1;
108     int ans=-inf;
109     if (ql<=mid) ans=max(ans,getmax(ls,l,mid,ql,qr));
110     if (qr>mid) ans=max(ans,getmax(rs,mid+1,r,ql,qr));
111     return ans;
112 }
113 
114 int findmax(int a,int b){
115     int res=-inf;
116     while (top[a]!=top[b]){
117         if (depth[top[a]]<depth[top[b]]){
118             swap(a,b);
119         }
120         res=max(res,getmax(1,1,n,num[top[a]],num[a]));
121         a=fa[top[a]];
122     }
123     if (depth[a]>depth[b]) swap(a,b); 
124     res=max(res,getmax(1,1,n,num[a],num[b]));
125     return res;    
126 }
127 int findsum(int a,int b){
128     int res=0;
129     while (top[a]!=top[b]){
130         if (depth[top[a]]<depth[top[b]]){
131             swap(a,b);
132         }
133         res+=getsum(1,1,n,num[top[a]],num[a]);
134         a=fa[top[a]];
135     }
136     if (depth[a]>depth[b]) swap(a,b);
137     res+=getsum(1,1,n,num[a],num[b]);
138     return res;    
139 }
140 
141 int main(){
142     scanf("%d",&n);
143     for (int i=1;i<n;++i){
144         scanf("%d%d",&ra,&rb);
145         addedge(ra,rb);
146     }
147     for (int i=1;i<=n;++i)
148       scanf("%d",&val[i]);
149     dfsa(1);
150     dfsb(1);
151     maketree(1,1,n);
152     scanf("%d",&m);
153     char re[10];
154     while (m--){
155         scanf("%s%d%d",re,&ra,&rb);
156         if (re[0]=='C') change(1,1,n,num[ra],rb);
157         else if (re[1]=='M') printf("%d\n",findmax(ra,rb));
158         else printf("%d\n",findsum(ra,rb));
159     }
160     return 0;
161 }
View Code

 

posted @ 2017-11-13 22:43  lonlyn  阅读(156)  评论(0编辑  收藏  举报