1. 程式人生 > 實用技巧 >[ZJOI2008]樹的統計

[ZJOI2008]樹的統計

題目描述

一棵樹上有nn個節點,編號分別為11到nn,每個節點都有一個權值ww。

我們將以下面的形式來要求你對這棵樹完成一些操作:

I.CHANGE u t: 把結點uu的權值改為tt。

II.QMAX u v: 詢問從點uu到點vv的路徑上的節點的最大權值。

III.QSUM u v: 詢問從點uu到點vv的路徑上的節點的權值和。

注意:從點uu到點vv的路徑上的節點包括uu和vv本身。

輸入格式

輸入檔案的第一行為一個整數nn,表示節點的個數。

接下來n-1n1行,每行22個整數aa和bb,表示節點aa和節點bb之間有一條邊相連。

接下來一行nn個整數,第ii個整數w_iwi表示節點ii的權值。

接下來11行,為一個整數qq,表示操作的總數。

接下來qq行,每行一個操作,以CHANGE u t或者QMAX u v或者QSUM u v的形式給出。

輸出格式

對於每個QMAX或者QSUM的操作,每行輸出一個整數表示要求輸出的結果。

輸入輸出樣例

輸入
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
輸出
4
1
2
2
10
6
5
6
5
16

說明/提示

對於100 \%100%的資料,保證1\le n \le 3\times 10^41n3×104,0\le q\le 2\times 10^50q2×105。

中途操作中保證每個節點的權值ww在-3\times 10^43×104到3\times 10^43×104之間。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int head[100001],tot,n,q,w[100001],d[1000001],fa[1000001],size[1000001],sum,top[1000001],pos[10000001
]; 4 struct data { 5 int to,nxt; 6 } e[1000001]; 7 struct SegmentTree { 8 int sum,l,r,mx; 9 #define l(x) tree[x].l 10 #define r(x) tree[x].r 11 #define sum(x) tree[x].sum 12 #define mx(x) tree[x].mx 13 } tree[4000004]; 14 void add(int x,int y) { 15 e[++tot].to=y; 16 e[tot].nxt=head[x]; 17 head[x]=tot; 18 } 19 void build(int p,int l,int r) { 20 l(p)=l,r(p)=r; 21 if(l==r) 22 return; 23 int mid=l+r>>1; 24 build(p<<1,l,mid); 25 build(p<<1|1,mid+1,r); 26 } 27 void change(int p,int x,int v) { 28 if(l(p)==r(p)) { 29 sum(p)=v; 30 mx(p)=v; 31 return; 32 } 33 int mid=l(p)+r(p)>>1; 34 if(x<=mid) change(p<<1,x,v); 35 else change(p<<1|1,x,v); 36 mx(p)=max(mx(p<<1),mx(p<<1|1)); 37 sum(p)=sum(p<<1)+sum(p<<1|1); 38 } 39 int query_sum(int p,int l,int r) { 40 if(l<=l(p)&&r>=r(p)) 41 return sum(p); 42 int val=0; 43 int mid=l(p)+r(p)>>1; 44 if(l<=mid) val+=query_sum(p<<1,l,r); 45 if(r>mid) val+=query_sum(p<<1|1,l,r); 46 return val; 47 } 48 int query_mx(int p,int l,int r) { 49 if(l<=l(p)&&r>=r(p)) 50 return mx(p); 51 int val=-(1<<30); 52 int mid=l(p)+r(p)>>1; 53 if(l<=mid) val=max(val,query_mx(p<<1,l,r)); 54 if(r>mid) val=max(val,query_mx(p<<1|1,l,r)); 55 return val; 56 } 57 void dfs1(int x) { 58 size[x]=1; 59 for(int i=head[x]; i; i=e[i].nxt) { 60 int v=e[i].to; 61 if(v==fa[x]) continue; 62 fa[v]=x; 63 d[v]=d[x]+1; 64 dfs1(v); 65 size[x]+=size[v]; 66 } 67 } 68 void dfs2(int x,int t) { //jiedian top 69 int node=0; 70 pos[x]=++sum; 71 top[x]=t; 72 for(int i=head[x]; i; i=e[i].nxt) 73 if(d[e[i].to]>d[x]&&size[e[i].to]>size[node]) 74 node=e[i].to; 75 if(node==0) 76 return; 77 dfs2(node,t); 78 for(int i=head[x]; i; i=e[i].nxt) 79 if(d[e[i].to]>d[x]&&node!=e[i].to) 80 dfs2(e[i].to,e[i].to); 81 } 82 int solve_sum(int x,int y) { 83 int val=0; 84 while(top[x]!=top[y]) { 85 if(d[top[x]]<d[top[y]]) swap(x,y); 86 val+=query_sum(1,pos[top[x]],pos[x]); 87 x=fa[top[x]]; 88 } 89 if(pos[x]>pos[y]) swap(x,y); 90 val+=query_sum(1,pos[x],pos[y]); 91 return val; 92 } 93 int solve_mx(int x,int y) { 94 int val=-(1<<30); 95 while(top[x]!=top[y]) { 96 if(d[top[x]]<d[top[y]]) swap(x,y); 97 val=max(val,query_mx(1,pos[top[x]],pos[x])); 98 x=fa[top[x]]; 99 } 100 if(pos[x]>pos[y]) swap(x,y); 101 val=max(val,query_mx(1,pos[x],pos[y])); 102 return val; 103 } 104 void init() { 105 scanf("%d",&n); 106 for(int i=1,x,y; i<n; i++) 107 scanf("%d%d",&x,&y),add(x,y),add(y,x); 108 for(int i=1; i<=n; i++) 109 scanf("%d",&w[i]); 110 } 111 void solve() { 112 build(1,1,n); 113 for(int i=1; i<=n; i++) 114 change(1,pos[i],w[i]); 115 scanf("%d",&q); 116 for(int i=1; i<=q; i++) { 117 char c[10]; 118 int x,y; 119 scanf("%s%d%d",c,&x,&y); 120 if(c[0]=='C') 121 change(1,pos[x],y); 122 else { 123 if(c[1]=='M') 124 printf("%d\n",solve_mx(x,y)); 125 else 126 printf("%d\n",solve_sum(x,y)); 127 } 128 } 129 } 130 int main() { 131 init(); 132 dfs1(1); 133 dfs2(1,1); 134 solve(); 135 return 0; 136 }
View Code