[关闭]
@y20070316 2017-04-22T11:11:56.000000Z 字数 3623 阅读 902

BZOJ 3572 - 世界树

题目 虚树


题意

  给定一棵树, 多组询问, 求每个点占据的点的数量.
  

分析

  对于每组询问, 很明显先构造出虚树, 并求出到 每一个点到占领它的点的最短距离, 以及 占领它的点的编号.
  我们将 不在虚树边上的点 放在 虚树的点上 , 在虚树边上的点 放在 虚树的边上 , 分开考虑 虚树的边 以及 虚树的点 的贡献.
  虚树的点: 我们只要求出每个虚树的点上有多少个实际的点即可. 这可以轻易地统计.
  虚树的边: 我们找到这一条边的中点, 将中点以上的归在 , 将中点以下的归在 .

一个经典的模型

问题描述:

  已知 , 的中点, 求 的距离.

分析:
  假设 , 即 重合, 考虑简化版的问题.
  很明显有 .

  假设 , 即 重合.
  假设 的速度均为 个单位每秒, 那么 出发 秒后出发, 此时 走的距离相同, 而总距离是 , 所以 .

  发现二者可以合并.
  即 . 这个结论是很有用的, 当 为负数, 即 的右边时, 结论依然成立.

实现

虚树的构建:
  虚树需要维护的信息: t[N],tot, fa[N] .

  1. int cmp(int i,int j) { return dfn[i]<dfn[j]; }
  2. void Virtual(void) {
  3. sort(h+1,h+m+1,cmp);
  4. F(i,1,m) {
  5. int now=h[i];
  6. if (top==0)
  7. fa[ s[++top]=t[++tot]=now ]=0;
  8. else {
  9. int x=LCA(s[top],now);
  10. for (;dep[s[top]]>dep[x];s[top--]=0)
  11. if (dep[s[top-1]]<=dep[x]) fa[s[top]]=x;
  12. if (x!=s[top])
  13. fa[ s[top+1]=t[++tot]=x ]=s[top]; top++;
  14. fa[ s[++top]=t[++tot]=now ]=x;
  15. }
  16. }
  17. }

中间变量:
  如果我们进行了重标号, 然后枚举的是标号, 那么每次考虑设中间变量, 表示重标号的原编号.
  这样写起来会简洁很多.

  1. F(i,1,tot) {
  2. int x=t[i]; ans[pos[near[x].S]]+=w[x];
  3. }

树上倍增:
  树上倍增可以支持:
    1. 求LCA
    2. 一个点向上跳若干步
    3. 一个点跳到深度为 的祖先
  本题就使用了3, 我第一次写.

代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cstdlib>
  4. #include <cctype>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <vector>
  8. #include <utility>
  9. using namespace std;
  10. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  11. #define P(i,a,b) for (int i=(a);i>=(b);i--)
  12. #define L first
  13. #define S second
  14. const int N=300005;
  15. int n; vector<int> g[N];
  16. int siz[N];
  17. int dfn[N],ind;
  18. int c,dep[N],pre[20][N];
  19. int q;
  20. int m,h[N],pos[N],ans[N];
  21. int t[N],tot,fa[N];
  22. int s[N],top;
  23. int w[N];
  24. pair<int,int> near[N];
  25. int rd(void) {
  26. int x=0,f=1; char c=getchar();
  27. for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
  28. for (;isdigit(c);c=getchar()) x=x*10+c-'0';
  29. return x*f;
  30. }
  31. void Prework(int x) {
  32. siz[x]=1; dfn[x]=++ind;
  33. for (vector<int>::iterator v=g[x].begin();v!=g[x].end();v++)
  34. if (pre[0][x]!=*v) {
  35. dep[*v]=dep[x]+1; pre[0][*v]=x;
  36. Prework(*v);
  37. siz[x]+=siz[*v];
  38. }
  39. }
  40. int LCA(int x,int y) {
  41. if (dep[x]<dep[y]) swap(x,y);
  42. P(i,c,0) if (dep[pre[i][x]]>=dep[y]) x=pre[i][x];
  43. if (x==y) return x;
  44. P(i,c,0) if (pre[i][x]!=pre[i][y]) x=pre[i][x],y=pre[i][y];
  45. return pre[0][x];
  46. }
  47. int Skip(int x,int d) { P(i,c,0) if (dep[pre[i][x]]>=d) x=pre[i][x]; return x; }
  48. int cmp(int i,int j) { return dfn[i]<dfn[j]; }
  49. void Virtual(void) {
  50. sort(h+1,h+m+1,cmp);
  51. F(i,1,m) {
  52. int now=h[i];
  53. if (top==0) {
  54. fa[ s[++top]=t[++tot]=now ]=0;
  55. near[now]=make_pair(0,now);
  56. w[now]=siz[now];
  57. }
  58. else {
  59. int x=LCA(s[top],now);
  60. for (;dep[s[top]]>dep[x];s[top--]=0)
  61. if (dep[s[top-1]]<=dep[x]) fa[s[top]]=x;
  62. if (x!=s[top]) {
  63. fa[ s[top+1]=t[++tot]=x ]=s[top]; top++;
  64. near[x]=make_pair(~0u>>2,0);
  65. w[x]=siz[x];
  66. }
  67. fa[ s[++top]=t[++tot]=now ]=x;
  68. near[now]=make_pair(0,now);
  69. w[now]=siz[now];
  70. }
  71. }
  72. }
  73. int main(void) {
  74. #ifndef ONLINE_JUDGE
  75. freopen("sdchr.in","r",stdin);
  76. #endif
  77. n=rd(); F(i,1,n-1) { int x=rd(),y=rd(); g[x].push_back(y); g[y].push_back(x); }
  78. c=(int)log2(n); dep[1]=1; pre[0][1]=1;
  79. Prework(1);
  80. F(i,1,c) F(j,1,n) pre[i][j]=pre[i-1][pre[i-1][j]];
  81. q=rd();
  82. F(cas,1,q) {
  83. m=rd(); F(i,1,m) h[i]=rd(),pos[h[i]]=i;
  84. Virtual();
  85. sort(t+1,t+tot+1,cmp);
  86. P(i,tot,2) {
  87. int x=t[i],f=fa[x];
  88. near[f]=min(near[f],make_pair(near[x].L+(dep[x]-dep[f]),near[x].S));
  89. }
  90. F(i,2,tot) {
  91. int x=t[i],f=fa[x];
  92. near[x]=min(near[x],make_pair(near[f].L+(dep[x]-dep[f]),near[f].S));
  93. }
  94. F(i,1,tot) {
  95. int x=t[i],f=fa[x],d=dep[x]-dep[f];
  96. if (i==1) ans[pos[near[x].S]]+=n-siz[x];
  97. else {
  98. int nx=Skip(x,dep[f]+1),sum=siz[nx]-siz[x]; w[f]-=siz[nx];
  99. if (near[x].S==near[f].S)
  100. ans[pos[near[x].S]]+=sum;
  101. else {
  102. int M=dep[x]-(d-near[x].L+near[f].L)/2;
  103. if ( (d-near[x].L+near[f].L)%2==0 && near[f].S<near[x].S ) M++;
  104. int nx2=Skip(x,M); int sum2=siz[nx2]-siz[x];
  105. ans[pos[near[x].S]]+=sum2;
  106. ans[pos[near[f].S]]+=sum-sum2;
  107. }
  108. }
  109. }
  110. F(i,1,tot) {
  111. int x=t[i]; ans[pos[near[x].S]]+=w[x];
  112. }
  113. F(i,1,m) printf("%d ",ans[i]); printf("\n");
  114. F(i,1,tot) near[t[i]]=make_pair(0,0);
  115. F(i,1,tot) w[t[i]]=0;
  116. while (top>0) s[top--]=0;
  117. F(i,1,tot) fa[t[i]]=0; F(i,1,tot) t[i]=0; tot=0;
  118. F(i,1,m) pos[h[i]]=0; F(i,1,m) h[i]=ans[i]=0; m=0;
  119. }
  120. return 0;
  121. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注