2008年省队选拔赛浙江
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
注意:从点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\n",max(solve_mx(x,t),solve_mx(y,t))); 184 else 185 printf("%d\n",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 }
原文:http://www.cnblogs.com/grhyxzc/p/5134397.html