[关闭]
@Chilling 2017-02-18T11:18:13.000000Z 字数 3881 阅读 1004

BZOJ-1036: 树的统计Count(点权)

树链剖分 线段树


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

部分摘自starszys的博客,但是这个博客上面的题是边权,因此以下内容有一定的修改……

树链,就是树上的路径。剖分,就是把路径分类为重链轻链

重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
轻儿子:v的其它子节点。
重边:点v与其重儿子的连边。
轻边:点v与其轻儿子的连边。
重链:由重边连成的路径。
轻链:轻边。

剖分后的树有如下性质:
性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v];
性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。

分析:对于这道题来说,我们应该求出如下内容:

siz[u]表示以u为根的子树的节点数;
dep[u]表示u的深度(根深度为1);
fa[u]表示u的父亲,son[u]表示与u在同一重链上的u的儿子节点(重儿子);
top[u]表示u所在的重链的顶端节点;
pre[u]表示u的新编号。

dfs1:求出siz[u],dep[u],fa[u],son[u];
dfs2:对于某点u,若它不是叶子节点,显然有top[son[u]] = top[u];节点u重新编号为pre[u]之后,valnow[pre[u]]=val[u];此时,为了使一条重链各边在线段树中连续分布,应当进行dfs2(son[u],u,id)。(id为重链顶端节点)
而对于u个各个轻儿子,top[v]=v。

询问:

  • 询问(u,v)路径上的最值,首先需要判断u和v是否在同一条重链上,若在同一条重链上,使u深v浅,查询(pre[v],pre[u])区间内的最值即可;
  • 若u,v不在同一条重链上,那么判断u和v重链顶端的深度,使top[u]更深,先查询pre[top[u]]到pre[u],那么u点所在的这部分重链就已经查询完毕了;接着u等于fa[top[u]],继续以上操作,直到u和v在同一条重链上。
  • 查询部分即线段树。

  1. #include<stdio.h>
  2. #include<vector>
  3. #include<algorithm>
  4. #include<string.h>
  5. #define INF 0x3f3f3f3f
  6. const int maxn=30005;
  7. using namespace std;
  8. int n;
  9. int val[maxn];
  10. int siz[maxn],dep[maxn],fa[maxn],son[maxn];//dfs1
  11. int pre[maxn];//对于节点v,pre[v]对应新编号++clk
  12. int valnow[maxn];//节点新编号后对应的值 valnow[clk]=val[v]
  13. int top[maxn];//v节点所在重链顶端的点
  14. int clk;
  15. struct node
  16. {
  17. int l,r,maxs,sum;
  18. }s[maxn*4];
  19. vector<int> V[maxn];
  20. void dfs1(int u,int f,int d)//维护fa,dep,siz,son
  21. {
  22. dep[u]=d; //深度
  23. fa[u]=f; //u的父亲
  24. siz[u]=1; //以u为根的子树节点
  25. //son[u]=0; //u的重儿子
  26. for(int i=0;i<V[u].size();i++)
  27. {
  28. int v=V[u][i];
  29. if(v==f) continue;
  30. dfs1(v,u,d+1);
  31. if(siz[v]>siz[son[u]]) //更新重儿子
  32. son[u]=v;
  33. siz[u]+=siz[v];
  34. }
  35. }
  36. void dfs2(int u,int f,int id) //id为u所在的顶端节点
  37. {
  38. top[u]=id;
  39. pre[u]=++clk;
  40. valnow[clk]=val[u];
  41. if(!son[u]) return; //叶子节点,无重儿子
  42. dfs2(son[u],u,id);
  43. for(int i=0;i<V[u].size();i++)
  44. {
  45. int v=V[u][i];
  46. if(v==f||v==son[u]) continue;
  47. dfs2(v,u,v);
  48. }
  49. }
  50. void build(int id,int l,int r)
  51. {
  52. s[id].l=l;
  53. s[id].r=r;
  54. if(l==r)
  55. s[id].maxs=s[id].sum=valnow[l];
  56. else
  57. {
  58. int mid=(l+r)/2;
  59. build(id*2,l,mid);
  60. build(id*2+1,mid+1,r);
  61. s[id].maxs=max(s[id*2].maxs,s[id*2+1].maxs);
  62. s[id].sum=s[id*2].sum+s[id*2+1].sum;
  63. }
  64. }
  65. void rep(int id,int x,int num)
  66. {
  67. if(s[id].l==s[id].r)
  68. s[id].maxs=s[id].sum=num;
  69. else
  70. {
  71. int mid=(s[id].l+s[id].r)/2;
  72. if(x<=mid)
  73. rep(id*2,x,num);
  74. else
  75. rep(id*2+1,x,num);
  76. s[id].maxs=max(s[id*2].maxs,s[id*2+1].maxs);
  77. s[id].sum=s[id*2].sum+s[id*2+1].sum;
  78. }
  79. }
  80. int qmax(int id,int l,int r)
  81. {
  82. if(l<=s[id].l&&s[id].r<=r)
  83. return s[id].maxs;
  84. int mid=(s[id].l+s[id].r)/2;
  85. if(r<=mid)
  86. return qmax(id*2,l,r);
  87. else if(l>mid)
  88. return qmax(id*2+1,l,r);
  89. else
  90. return max(qmax(id*2,l,r),qmax(id*2+1,l,r));
  91. }
  92. int qsum(int id,int l,int r)
  93. {
  94. if(l<=s[id].l&&s[id].r<=r)
  95. return s[id].sum;
  96. int mid=(s[id].l+s[id].r)/2;
  97. if(r<=mid)
  98. return qsum(id*2,l,r);
  99. else if(l>mid)
  100. return qsum(id*2+1,l,r);
  101. else
  102. return qsum(id*2,l,r)+qsum(id*2+1,l,r);
  103. }
  104. int ansmax(int u,int v)
  105. {
  106. int ans=-INF;
  107. while(top[u]!=top[v])//不在一条重链上
  108. {
  109. if(dep[top[u]]<dep[top[v]])
  110. swap(u,v); //u重链顶端更深
  111. ans=max(ans,qmax(1,pre[top[u]],pre[u]));
  112. u=fa[top[u]];
  113. }
  114. if(dep[u]<dep[v])
  115. swap(u,v);
  116. ans=max(ans,qmax(1,pre[v],pre[u]));
  117. return ans;
  118. }
  119. int anssum(int u,int v)
  120. {
  121. int ans=0;
  122. while(top[u]!=top[v])
  123. {
  124. if(dep[top[u]]<dep[top[v]])
  125. swap(u,v); //u重链顶端更深
  126. ans+=qsum(1,pre[top[u]],pre[u]);
  127. u=fa[top[u]];
  128. }
  129. if(dep[u]<dep[v])
  130. swap(u,v);
  131. ans+=qsum(1,pre[v],pre[u]);
  132. return ans;
  133. }
  134. int main()
  135. {
  136. int x,y,q;
  137. char ch[9];
  138. scanf("%d",&n);
  139. for(int i=1;i<n;i++)
  140. {
  141. scanf("%d%d",&x,&y);
  142. V[x].push_back(y);
  143. V[y].push_back(x);
  144. }
  145. for(int i=1;i<=n;i++)
  146. scanf("%d",&val[i]);
  147. dfs1(1,0,1);
  148. dfs2(1,0,1);
  149. build(1,1,n);
  150. scanf("%d",&q);
  151. while(q--)
  152. {
  153. scanf("%s%d%d",ch,&x,&y);
  154. if(ch[3]=='N')
  155. rep(1,pre[x],y);
  156. else if(ch[3]=='X')
  157. printf("%d\n",ansmax(x,y));
  158. else
  159. printf("%d\n",anssum(x,y));
  160. }
  161. return 0;
  162. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注