[ZJOI2008]树的统计

题目描述

一棵树上有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之间。

[思路]

树链剖分 + 线段树单点修改 + 维护区间最大和区间和

[code]

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 using namespace std;
  5 int n,q,a[4*100005];
  6 struct Edge{
  7     int u,v,next;
  8 }G[100005];
  9 int tot=0,head[100005];
 10 int size[100005],wson[100005],fa[100005],d[100005],top[100005];
 11 int tpos[100005],pre[100005],cnt=0;
 12 inline void addedge(int u,int v){
 13     G[++tot].u=u;G[tot].v=v;G[tot].next=head[u];head[u]=tot;
 14     G[++tot].u=v;G[tot].v=u;G[tot].next=head[v];head[v]=tot;
 15 }
 16 void dfs1(int u,int f){
 17     size[u]=1;
 18     for (int i=head[u];i;i=G[i].next){
 19         int v=G[i].v;if (v==f)continue;
 20         d[v]=d[u]+1;fa[v]=u;
 21         dfs1(v,u);
 22         size[u]+=size[v];
 23         if (size[v]>size[wson[u]])wson[u]=v;
 24     }
 25 }
 26 void dfs2(int u,int TP){
 27     tpos[u]=++cnt;
 28     pre[cnt]=u;
 29     top[u]=TP;
 30     if (wson[u])dfs2(wson[u],TP);
 31     for (int i=head[u];i;i=G[i].next){
 32         int v=G[i].v;
 33         if (v==fa[u]||v==wson[u])continue;
 34         dfs2(v,v);
 35     }
 36 }
 37 int sumv[4*100005],maxv[4*100005];
 38 inline void pushup(int o){
 39     sumv[o]=sumv[o*2]+sumv[o*2+1];
 40     maxv[o]=max(maxv[o*2],maxv[o*2+1]);
 41 }
 42 void build(int o,int l,int r){
 43     int mid=(l+r)/2;
 44     if (l==r){
 45         sumv[o]=maxv[o]=a[pre[l]];
 46         return;
 47     }
 48     build(o*2,l,mid);
 49     build(o*2+1,mid+1,r);
 50     pushup(o);
 51 }
 52 void update(int o,int l,int r,int q,int v){
 53     int mid=(l+r)/2;
 54     if (l==r){sumv[o]=maxv[o]=v;return;}
 55     if (q<=mid)update(o*2,l,mid,q,v);
 56     else update(o*2+1,mid+1,r,q,v);
 57     pushup(o);
 58 }
 59 int querysum(int o,int l,int r,int ql,int qr){
 60     int mid=(l+r)/2,ans=0;
 61     if (ql<=l&&r<=qr)return sumv[o];
 62     if (ql<=mid)ans+=querysum(o*2,l,mid,ql,qr);
 63     if (qr>mid)ans+=querysum(o*2+1,mid+1,r,ql,qr);
 64     pushup(o);
 65     return ans;
 66 }
 67 int querymax(int o,int l,int r,int ql,int qr){
 68     int mid=(l+r)/2,ans=-1<<30;
 69     if (ql<=l&&r<=qr)return maxv[o];
 70     if (ql<=mid)ans=max(ans,querymax(o*2,l,mid,ql,qr));
 71     if (qr>mid)ans=max(ans,querymax(o*2+1,mid+1,r,ql,qr));
 72     pushup(o);
 73     return ans;
 74 }
 75 int qsum(int u,int v){
 76     int ans=0;
 77     while (top[u]!=top[v]){
 78         if (d[top[u]]<d[top[v]])swap(u,v);
 79         ans+=querysum(1,1,n,tpos[top[u]],tpos[u]);
 80         u=fa[top[u]];
 81     }
 82     if (d[u]<d[v])swap(u,v);
 83     ans+=querysum(1,1,n,tpos[v],tpos[u]);
 84     return ans;
 85 }
 86 int qmax(int u,int v){
 87     int ans=-1<<30;
 88     while (top[u]!=top[v]){
 89         if (d[top[u]]<d[top[v]])swap(u,v);
 90         ans=max(ans,querymax(1,1,n,tpos[top[u]],tpos[u]));
 91         u=fa[top[u]];
 92     }
 93     if (d[u]<d[v])swap(u,v);
 94     ans=max(ans,querymax(1,1,n,tpos[v],tpos[u]));
 95     return ans;
 96 }
 97 int main(){
 98     memset(head,0,sizeof(head));
 99     memset(a,0,sizeof(a));
100     scanf("%d",&n);
101     for (int i=1;i<n;i++){
102         int u,v;
103         scanf("%d%d",&u,&v);
104         addedge(u,v);
105     }
106     for (int i=1;i<=n;i++)scanf("%d",&a[i]);
107     d[1]=1;
108     fa[1]=1;
109     dfs1(1,-1);
110     dfs2(1,1);
111     build(1,1,n);
112     scanf("%d",&q);
113     while (q--){
114         int x,y;
115         char s[10];
116         scanf("%s%d%d",s,&x,&y);
117         if (s[1]=='H')update(1,1,n,tpos[x],y);
118         if (s[1]=='M')printf("%d\n",qmax(x,y));
119         if (s[1]=='S')printf("%d\n",qsum(x,y));
120     }
121     return 0;
122 }

 

posted @ 2019-07-22 18:18  GTR_PaulFrank  阅读(160)  评论(0编辑  收藏  举报