2460 树的统计
2008年省队选拔赛浙江
一棵树上有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”的操作,每行输出一个整数表示要求输出的结果。
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%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
题解
裸的树链剖分...
树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护。
通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中size[v]是以v为根的子树的节点个数,全部由重边组成的路径是重路径,根据论文上的证明,任意一点到根的路径上存在不超过logn条轻边和logn条重路径。
这样我们考虑用数据结构来维护重路径上的查询,轻边直接查询。
通常用来维护的数据结构是线段树,splay较少见。
具体步骤
预处理
第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x]
以及祖先的信息fa[x][i]表示x往上距离为2^i的祖先
第二遍dfs
根节点为起点,向下拓展构建重链
选择最大的一个子树的根继承当前重链
其余节点,都以该节点为起点向下重新拉一条重链
给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。
把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可
修改操作
1、单独修改一个点的权值
根据其编号直接在数据结构中修改就行了。
2、修改点u和点v的路径上的权值
(1)若u和v在同一条重链上
直接用数据结构修改pos[u]至pos[v]间的值。
(2)若u和v不在同一条重链上
一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。
查询操作
查询操作的分析过程同修改操作
题目不同,选用不同的数据结构来维护值,通常有线段树和splay
代码:
树链剖分
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define INF 0x7fffffff 5 #define N 30005 6 #define M 60005 7 8 using namespace std; 9 10 int n,q,cnt,sz; 11 int fa[N][15],v[N],deep[N],size[N],head[N]; 12 int pos[N],belong[N]; 13 bool vis[N]; 14 struct node 15 { 16 int to; 17 int next; 18 }e[M]; 19 20 struct ss 21 { 22 int l; 23 int r; 24 int mx; 25 int sum; 26 }t[100005]; 27 28 void insert(int u,int v) 29 { 30 e[++cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; 31 e[++cnt].to=u; e[cnt].next=head[v]; head[v]=cnt; 32 } 33 34 void inint() 35 { 36 scanf("%d",&n); 37 for (int i=1;i<n;i++) 38 { 39 int x,y; 40 scanf("%d%d",&x,&y); 41 insert(x,y); 42 } 43 for (int i=1;i<=n;i++) scanf("%d",&v[i]); 44 } 45 46 void getree(int x) 47 { 48 size[x]=1; 49 vis[x]=1; 50 for (int i=1;i<=14;i++) 51 { 52 if (deep[x]<(1<<i)) break; 53 fa[x][i]=fa[fa[x][i-1]][i-1]; 54 } 55 for (int i=head[x];i;i=e[i].next) 56 { 57 if (vis[e[i].to]) continue; 58 deep[e[i].to]=deep[x]+1; 59 fa[e[i].to][0]=x; 60 getree(e[i].to); 61 size[x]+=size[e[i].to]; 62 } 63 } 64 65 void dfs(int x,int chain) 66 { 67 int k=0; 68 sz++; 69 pos[x]=sz; 70 belong[x]=chain; 71 for (int i=head[x];i;i=e[i].next) 72 if (deep[e[i].to]>deep[x]&&size[e[i].to]>size[k]) 73 k=e[i].to; 74 if (k==0) return; 75 dfs(k,chain); 76 for (int i=head[x];i;i=e[i].next) 77 if (deep[e[i].to]>deep[x]&&k!=e[i].to) 78 dfs(e[i].to,e[i].to); 79 } 80 81 int lca(int x,int y) 82 { 83 if (deep[x]<deep[y]) swap(x,y); 84 int t=deep[x]-deep[y]; 85 for (int i=0;i<=14;i++) 86 if ((1<<i)&t) x=fa[x][i]; 87 for (int i=14;i>=0;i--) 88 if (fa[x][i]!=fa[y][i]) 89 { 90 x=fa[x][i]; 91 y=fa[y][i]; 92 } 93 if (x==y) return x; 94 else return fa[x][0]; 95 } 96 97 void build(int k,int l,int r) 98 { 99 t[k].l=l; 100 t[k].r=r; 101 if (l==r) return; 102 int mid=(l+r)>>1; 103 build(k<<1,l,mid); 104 build(k<<1|1,mid+1,r); 105 } 106 107 void change(int k,int x,int y) 108 { 109 int l=t[k].l,r=t[k].r,mid=(l+r)>>1; 110 if (l==r) 111 { 112 t[k].sum=t[k].mx=y; 113 return; 114 } 115 if (x<=mid) change(k<<1,x,y); 116 else change(k<<1|1,x,y); 117 t[k].sum=t[k<<1].sum+t[k<<1|1].sum; 118 t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx); 119 } 120 121 int find_sum(int k,int x,int y) 122 { 123 int l=t[k].l,r=t[k].r,mid=(l+r)>>1; 124 if (l==x&&y==r) return t[k].sum; 125 if (y<=mid) return find_sum(k<<1,x,y); 126 else if (x>mid) return find_sum(k<<1|1,x,y); 127 else return find_sum(k<<1,x,mid)+find_sum(k<<1|1,mid+1,y); 128 } 129 130 int find_mx(int k,int x,int y) 131 { 132 int l=t[k].l,r=t[k].r,mid=(l+r)>>1; 133 if (l==x&&r==y) return t[k].mx; 134 if (y<=mid) return find_mx(k<<1,x,y); 135 else if (x>mid) return find_mx(k<<1|1,x,y); 136 else return max(find_mx(k<<1,x,mid),find_mx(k<<1|1,mid+1,y)); 137 } 138 139 int solve_mx(int x,int f) 140 { 141 int mx=-INF; 142 while(belong[x]!=belong[f]) 143 { 144 mx=max(mx,find_mx(1,pos[belong[x]],pos[x])); 145 x=fa[belong[x]][0]; 146 } 147 mx=max(mx,find_mx(1,pos[f],pos[x])); 148 return mx; 149 } 150 151 int solve_sum(int x,int f) 152 { 153 int sum=0; 154 while (belong[x]!=belong[f]) 155 { 156 sum+=find_sum(1,pos[belong[x]],pos[x]); 157 x=fa[belong[x]][0]; 158 } 159 sum+=find_sum(1,pos[f],pos[x]); 160 return sum; 161 } 162 163 void solve() 164 { 165 build(1,1,n); 166 for (int i=1;i<=n;i++) 167 change(1,pos[i],v[i]); 168 scanf("%d",&q); 169 char ch[6]; 170 for (int i=1;i<=q;i++) 171 { 172 int x,y; 173 scanf("%s%d%d",ch,&x,&y); 174 if (ch[0]=='C') 175 { 176 v[x]=y; 177 change(1,pos[x],y); 178 } 179 else 180 { 181 int t=lca(x,y); 182 if (ch[1]=='M') 183 printf("%d ",max(solve_mx(x,t),solve_mx(y,t))); 184 else 185 printf("%d ",solve_sum(x,t)+solve_sum(y,t)-v[t]); 186 } 187 } 188 } 189 190 int main() 191 { 192 inint(); 193 getree(1); 194 dfs(1,1); 195 solve(); 196 return 0; 197 }
块状树:
1 #include<bits/stdc++.h> 2 #define maxn (int)1e5+10 3 4 using namespace std; 5 6 vector<int>g[maxn],ge[maxn]; 7 int cnt,sqrtn,n,m; 8 int w[maxn],sum[maxn],mx[maxn],fa[maxn],deep[maxn],bel[maxn],size[maxn]; 9 10 void dfs(int u) 11 { 12 for(int i=0;i<g[u].size();i++) 13 { 14 int v=g[u][i]; 15 if(v==fa[u])continue; 16 fa[v]=u; 17 deep[v]=deep[u]+1; 18 if(size[bel[u]]<sqrtn) 19 { 20 size[bel[u]]++;bel[v]=bel[u]; 21 ge[u].push_back(v); 22 } 23 dfs(v); 24 } 25 } 26 27 void dfs(int u,int s,int maxx) 28 { 29 s+=w[u]; 30 sum[u]=s; 31 maxx=max(maxx,w[u]); 32 mx[u]=maxx; 33 for(int i=0;i<ge[u].size();i++) 34 dfs(ge[u][i],s,maxx); 35 } 36 37 void change(int u,int ww) 38 { 39 w[u]=ww; 40 if(bel[u]==u) dfs(u,0,INT_MIN); 41 else dfs(u,sum[fa[u]],mx[fa[u]]); 42 } 43 44 pair<int,int> qsumax(int u,int v) 45 { 46 int s=0,maxx=INT_MIN; 47 while(u!=v){ 48 if(deep[u]<deep[v])swap(u,v); 49 if(bel[u]==bel[v]) 50 { 51 s+=w[u];maxx=max(maxx,w[u]); 52 u=fa[u]; 53 } 54 else 55 { 56 if(deep[bel[u]]<deep[bel[v]])swap(u,v); 57 s+=sum[u],maxx=max(maxx,mx[u]); 58 u=fa[bel[u]]; 59 } 60 } 61 s+=w[u],maxx=max(maxx,w[u]); 62 return pair<int,int>(s,maxx); 63 } 64 65 int main() 66 { 67 scanf("%d",&n); 68 sqrtn=sqrt(n); 69 for (int i=1;i<n;i++) 70 { 71 int u,v; 72 scanf("%d%d",&u,&v); 73 g[u].push_back(v); 74 g[v].push_back(u); 75 } 76 for (int i=1;i<=n;i++) 77 scanf("%d",w+i),bel[i]=i,size[i]=1; 78 dfs(1); 79 int q; 80 for(int i=1;i<=n;i++)if(bel[i]==i) 81 dfs(i,0,INT_MIN); 82 scanf("%d",&q); 83 while (q--) 84 { 85 int x,y; 86 char op[5]; 87 scanf("%s%d%d",op,&x,&y); 88 if(op[0]=='C') change(x,y); 89 else 90 { 91 pair<int,int>anss=qsumax(x,y); 92 if(op[1]=='M') 93 printf("%d ",anss.second); 94 else printf("%d ",anss.first); 95 } 96 } 97 return 0; 98 }