1. 程式人生 > >【BZOJ1036】樹的統計

【BZOJ1036】樹的統計

urn iostream font wap mst 之間 print int sca

1036: [ZJOI2008]樹的統計Count

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 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

Sample Output

4
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】樹的統計