1036: [ZJOI2008]树的统计Count
Description
一棵树上有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”的操作,每行输出一个整数表示要求输出的结果。
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
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
1
2
2
10
6
5
6
5
16
裸树链剖分。。。写的时候要注意点权有负的情况,边是两倍,因为是双向边。。。
对于树链剖分实际上就是一个把一棵树变成很多条链,这样子在树上的操作就变成了区间操作,这样再依托于数据结构就好了。。。
不过对于一棵树,如何划分也是有标准的。。。对于一颗树我们设第i个点的儿子节点数为son[i],那么对于一个节点在它的所有儿子x中son[x]最大的称为重点。。。如果一条链上的所有点都是重点,那么这条链就是重链。。。这样一来一棵树就变成了一条一条的链,这样就可以变为区间操作了。。。
我们可以通过两次dfs来找到重链。。。第一次dfs可以求出一个节点的子节点个数,它的父节点。。。
void dfs(int x){ s[x]=1; for(int y=son[x]=0,i=head[x];i;i=e[i].next){ if(dep[y=e[i].go]==0){ dep[y]=dep[x]+1;fa[y]=x;dfs(y); s[x]+=s[y];if(s[y]>s[son[x]])son[x]=y; } } } void dfs2(int x,int chain){ p[x]=++cnt;top[x]=chain;a[p[x]]=w[x]; if(son[x])dfs2(son[x],chain); for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) if(y!=fa[x]&&y!=son[x])dfs2(y,y); }
然后第二次dfs来求出重链,然后用dfs的顺序对每个点重新编号,然后建立数据结构即可。。。
4 #include<iostream> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 #include<cstdio> 9 #include<algorithm> 10 #include<string> 11 #include<map> 12 #include<queue> 13 #include<vector> 14 #include<set> 15 #define inf 1000000000 16 #define maxn 30005 17 #define maxm 30005*2 18 #define eps 1e-10 19 #define ll long long 20 #define for0(i,n) for(int i=0;i<=(n);i++) 21 #define for1(i,n) for(int i=1;i<=(n);i++) 22 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 23 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 24 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 25 using namespace std; 26 int read() 27 { 28 int x=0,f=1;char ch=getchar(); 29 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 30 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 31 return x*f; 32 } 33 struct tree{ 34 int l,r,sum,mx; 35 }f[maxn*4]; 36 struct edge{ 37 int go,next; 38 }e[maxm]; 39 int head[maxn],w[maxn],top[maxn],fa[maxn],p[maxn],son[maxn],s[maxn],dep[maxn],a[maxn],tot,cnt; 40 void pushup(int i){ 41 f[i].sum=(f[i*2+1].sum+f[i*2].sum); 42 f[i].mx=max(f[i*2+1].mx,f[i*2].mx); 43 } 44 45 void build(int i,int left,int right){ 46 int mid=(left+right)/2; 47 f[i].mx=-inf;f[i].l=left;f[i].r=right; 48 if(left==right){ 49 f[i].sum=a[left]; 50 f[i].mx=a[left]; 51 return; 52 } 53 build(i*2,left,mid); 54 build(i*2+1,mid+1,right); 55 pushup(i); 56 } 57 58 void change(int i,int goal,int v){ 59 int mid=(f[i].l+f[i].r)/2; 60 if(f[i].l==f[i].r&&f[i].l==goal){ 61 f[i].mx=f[i].sum=v; 62 return; 63 } 64 if(mid>=goal)change(i*2,goal,v); 65 else change(i*2+1,goal,v); 66 pushup(i); 67 } 68 69 int query(int i,int left,int right) { 70 int mid=(f[i].l+f[i].r)/2; 71 if(f[i].l==left&&f[i].r==right) return f[i].sum; 72 if(mid>=right) return query(i*2,left,right); 73 if(mid<left) return query(i*2+1,left,right); 74 return (query(i*2,left,mid)+query(i*2+1,mid+1,right)); 75 } 76 77 int qmax(int i,int left,int right){ 78 int mid=(f[i].l+f[i].r)/2; 79 if(f[i].l==left&&f[i].r==right) return f[i].mx; 80 if(mid>=right) return qmax(i*2,left,right); 81 if(mid<left) return qmax(i*2+1,left,right); 82 return max(qmax(i*2,left,mid),qmax(i*2+1,mid+1,right)); 83 } 84 void insert(int u,int v){ 85 e[++tot].go=v;e[tot].next=head[u];head[u]=tot; 86 } 87 void ins(int u,int v){ 88 insert(u,v);insert(v,u); 89 } 90 void dfs(int x){ 91 s[x]=1; 92 for(int y=son[x]=0,i=head[x];i;i=e[i].next){ 93 if(dep[y=e[i].go]==0){ 94 dep[y]=dep[x]+1;fa[y]=x;dfs(y); 95 s[x]+=s[y];if(s[y]>s[son[x]])son[x]=y; 96 } 97 } 98 } 99 void dfs2(int x,int chain){ 100 p[x]=++cnt;top[x]=chain;a[p[x]]=w[x]; 101 if(son[x])dfs2(son[x],chain); 102 for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 103 if(y!=fa[x]&&y!=son[x])dfs2(y,y); 104 } 105 int solvesum(int x,int y){ 106 int ans=0; 107 while(top[x]!=top[y]){ 108 if(dep[top[x]]<dep[top[y]])swap(x,y); 109 ans+=query(1,p[top[x]],p[x]); 110 x=fa[top[x]]; 111 } 112 if(dep[x]>dep[y])swap(x,y); 113 ans+=query(1,p[x],p[y]); 114 return ans; 115 } 116 int solvemax(int x,int y){ 117 int ans=-inf; 118 while(top[x]!=top[y]){ 119 if(dep[top[x]]<dep[top[y]])swap(x,y); 120 ans=max(ans,qmax(1,p[top[x]],p[x])); 121 x=fa[top[x]]; 122 } 123 if(dep[x]>dep[y])swap(x,y); 124 ans=max(ans,qmax(1,p[x],p[y])); 125 return ans; 126 } 127 128 int main(){ 129 //freopen("input.txt","r",stdin); 130 //freopen("output.txt","w",stdout); 131 int n=read();dep[1]=1; 132 for1(i,n-1){ 133 int u=read(),v=read(); 134 ins(u,v); 135 } 136 for1(i,n)w[i]=read(); 137 dfs(1);dfs2(1,1); 138 build(1,1,n); 139 n=read(); 140 for1(i,n){ 141 char ch=getchar(); 142 while(ch!='Q'&&ch!='C')ch=getchar(); 143 if(ch=='Q'){ 144 ch=getchar(); 145 if(ch=='M'){ 146 int x=read(),y=read(); 147 printf("%d\n",solvemax(x,y)); 148 } 149 else{ 150 int x=read(),y=read(); 151 printf("%d\n",solvesum(x,y)); 152 } 153 } 154 else{ 155 int x=read(),y=read(); 156 change(1,p[x],y); 157 } 158 } 159 return 0; 160 }