1. 程式人生 > >[樹鏈剖分][線段樹] 洛谷 P2590 樹的統計

[樹鏈剖分][線段樹] 洛谷 P2590 樹的統計

scan () pri clu fine edge def class else

題目描述

一棵樹上有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 <cstdio> 
  2 #include <iostream>
  3 #include <cstring>
  4 #define N 100010
  5 #define inf 1000000000
  6 using namespace std;
7 struct edge{ int to,from; }e[N]; 8 int sum[4*N],mx[4*N],dep[N],size[N],fa[N],head[N],tid[N],rank[N],top[N],a[4*N],son[N],cnt,tot,n,m,q; 9 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; } 10 void dfs(int x,int pre) 11 { 12 fa[x]=pre,dep[x]=dep[pre]+1,size[x]=1; 13 for (int i=head[x];i;i=e[i].from) 14 if (e[i].to!=pre) 15 { 16 dfs(e[i].to,x),size[x]+=size[e[i].to]; 17 if (size[e[i].to]>size[son[x]]) son[x]=e[i].to; 18 } 19 } 20 void dfs1(int x,int pre) 21 { 22 tid[x]=++tot,rank[tot]=x,top[x]=pre; 23 if (son[x]) dfs1(son[x],pre); 24 for (int i=head[x];i;i=e[i].from) 25 if (e[i].to!=son[x]&&e[i].to!=fa[x]) 26 dfs1(e[i].to,e[i].to); 27 } 28 void build(int d,int l,int r) 29 { 30 if (l==r) 31 { 32 sum[d]=mx[d]=a[rank[l]]; 33 return; 34 } 35 int mid=(l+r)>>1; 36 build(d*2,l,mid),build(d*2+1,mid+1,r); 37 sum[d]=sum[d*2]+sum[d*2+1],mx[d]=max(mx[d*2],mx[d*2+1]); 38 } 39 void updata(int d,int l,int r,int x,int y) 40 { 41 if (l==r) 42 { 43 sum[d]=mx[d]=y; 44 return; 45 } 46 int mid=(l+r)>>1; 47 if (x<=mid) updata(d*2,l,mid,x,y); else updata(d*2+1,mid+1,r,x,y); 48 sum[d]=sum[d*2]+sum[d*2+1],mx[d]=max(mx[d*2],mx[d*2+1]); 49 } 50 int querymax(int d,int l,int r,int x,int y) 51 { 52 int ans=-inf,mid=(l+r)>>1; 53 if (x<=l&&r<=y) return mx[d]; 54 if (x<=mid) ans=max(ans,querymax(d*2,l,mid,x,y)); 55 if (y>mid) ans=max(ans,querymax(d*2+1,mid+1,r,x,y)); 56 sum[d]=sum[d*2]+sum[d*2+1],mx[d]=max(mx[d*2],mx[d*2+1]); 57 return ans; 58 } 59 int querysum(int d,int l,int r,int x,int y) 60 { 61 int ans=0,mid=(l+r)>>1; 62 if (x<=l&&r<=y) return sum[d]; 63 if (x<=mid) ans+=querysum(d*2,l,mid,x,y); 64 if (y>mid) ans+=querysum(d*2+1,mid+1,r,x,y); 65 sum[d]=sum[d*2]+sum[d*2+1],mx[d]=max(mx[d*2],mx[d*2+1]); 66 return ans; 67 } 68 int getsum(int u,int v) 69 { 70 int ans=0; 71 while (top[u]!=top[v]) 72 { 73 if (dep[top[u]]<dep[top[v]]) swap(u,v); 74 ans+=querysum(1,1,n,tid[top[u]],tid[u]); 75 u=fa[top[u]]; 76 } 77 if (dep[u]<dep[v]) swap(u,v); 78 ans+=querysum(1,1,n,tid[v],tid[u]); 79 return ans; 80 } 81 int getmax(int u,int v) 82 { 83 int ans=-inf; 84 while (top[u]!=top[v]) 85 { 86 if (dep[top[u]]<dep[top[v]]) swap(u,v); 87 ans=max(ans,querymax(1,1,n,tid[top[u]],tid[u])); 88 u=fa[top[u]]; 89 } 90 if (dep[u]<dep[v]) swap(u,v); 91 ans=max(ans,querymax(1,1,n,tid[v],tid[u])); 92 return ans; 93 } 94 int main() 95 { 96 scanf("%d",&n); 97 for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x); 98 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 99 dfs(1,0); fa[1]=1,dfs1(1,1); build(1,1,n); 100 scanf("%d",&q); 101 while (q--) 102 { 103 char ch[10]; int x,y; 104 scanf("%s%d%d",ch,&x,&y); 105 if (ch[1]==H) updata(1,1,n,tid[x],y); 106 if (ch[1]==M) printf("%d\n",getmax(x,y)); 107 if (ch[1]==S) printf("%d\n",getsum(x,y)); 108 } 109 }

[樹鏈剖分][線段樹] 洛谷 P2590 樹的統計