bzoj1036 [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本身
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”的操作,每行输出一个整数表示要求输出的结果。
树剖模板。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 8 const int INF=1e9+7,NN=30007,MM=1e5+7; 9 10 int n,m,sz; 11 int a[NN],deep[NN],size[NN],fa[NN],pos[NN],bl[NN]; 12 int cnt,head[NN],next[MM],rea[MM]; 13 struct Node 14 { 15 int l,r,mx,sum; 16 }tree[MM]; 17 18 void add(int u,int v) 19 { 20 cnt++; 21 next[cnt]=head[u]; 22 head[u]=cnt; 23 rea[cnt]=v; 24 } 25 void dfs_init(int x) 26 { 27 size[x]=1; 28 for (int i=head[x];i!=-1;i=next[i]) 29 { 30 int v=rea[i]; 31 if (v==fa[x]) continue; 32 deep[v]=deep[x]+1; 33 fa[v]=x; 34 dfs_init(v); 35 size[x]+=size[v]; 36 } 37 } 38 void dfs_make(int x,int chain)//chain表示重链首的编号 39 { 40 int k=0;//找重链 41 sz++; 42 pos[x]=sz;//分配编号; 43 bl[x]=chain; 44 for (int i=head[x];i!=-1;i=next[i]) 45 { 46 int v=rea[i]; 47 if (deep[v]>deep[x]&&size[v]>size[k]) k=v; 48 } 49 if (k==0) return; 50 dfs_make(k,chain); 51 for (int i=head[x];i!=-1;i=next[i]) 52 { 53 int v=rea[i]; 54 if (deep[v]>deep[x]&&k!=v) dfs_make(v,v); 55 } 56 } 57 void build(int k,int l,int r) 58 { 59 tree[k].l=l,tree[k].r=r; 60 if (l==r) return; 61 int mid=(l+r)>>1; 62 build(k<<1,l,mid),build((k<<1)+1,mid+1,r); 63 } 64 void change(int k,int x,int y) 65 { 66 int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1; 67 if (l==r){tree[k].sum=tree[k].mx=y;return;} 68 if (x<=mid) change(k<<1,x,y); 69 else change(k<<1|1,x,y); 70 tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum; 71 tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx); 72 } 73 int query_sum(int k,int x,int y) 74 { 75 int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1; 76 if (l==x&&r==y) return tree[k].sum; 77 if (y<=mid) return query_sum(k<<1,x,y); 78 else if (x>mid) return query_sum(k<<1|1,x,y); 79 else return query_sum(k<<1,x,mid)+query_sum(k<<1|1,mid+1,y); 80 } 81 int query_max(int k,int x,int y) 82 { 83 int l=tree[k].l,r=tree[k].r,mid=(l+r)>>1; 84 if (l==x&&y==r) return tree[k].mx; 85 if (y<=mid) return query_max(k<<1,x,y); 86 else if (x>mid) return query_max(k<<1|1,x,y); 87 else return max(query_max(k<<1,x,mid),query_max(k<<1|1,mid+1,y)); 88 } 89 int solve_sum(int x,int y) 90 { 91 int sum=0; 92 while (bl[x]!=bl[y])//表示标记不同 93 { 94 if (deep[bl[x]]<deep[bl[y]]) swap(x,y); 95 sum+=query_sum(1,pos[bl[x]],pos[x]); 96 x=fa[bl[x]]; //跳完整条重链。 97 } 98 if (pos[x]>pos[y]) swap(x,y); 99 sum+=query_sum(1,pos[x],pos[y]); 100 return sum; 101 } 102 int solve_max(int x,int y) 103 { 104 int mx=-INF; 105 while (bl[x]!=bl[y]) 106 { 107 if (deep[bl[x]]<deep[bl[y]]) swap(x,y); 108 mx=max(mx,query_max(1,pos[bl[x]],pos[x])); 109 x=fa[bl[x]]; 110 } 111 if (pos[x]>pos[y]) swap(x,y); 112 mx=max(mx,query_max(1,pos[x],pos[y])); 113 return mx; 114 } 115 int main() 116 { 117 memset(head,-1,sizeof(head)); 118 scanf("%d",&n); 119 for (int i=1;i<n;i++) 120 { 121 int x,y; 122 scanf("%d%d",&x,&y); 123 add(x,y),add(y,x); 124 } 125 for (int i=1;i<=n;i++) 126 scanf("%d",&a[i]); 127 dfs_init(1); 128 dfs_make(1,1); 129 build(1,1,n);//建树。 130 for (int i=1;i<=n;i++) 131 change(1,pos[i],a[i]); 132 scanf("%d",&m); 133 char c[10]; 134 for (int i=1;i<=m;i++) 135 { 136 int x,y; 137 scanf("%s%d%d",c,&x,&y); 138 if (c[0]=='C') 139 { 140 a[x]=y; 141 change(1,pos[x],y); 142 } 143 else 144 { 145 if (c[1]=='M') printf("%d\n",solve_max(x,y)); 146 else printf("%d\n",solve_sum(x,y)); 147 } 148 } 149 }