第一次打“真正的”动态点分

如果树是静态的,直接点分:用$d_x$代表$x$到分治中心的距离,限制条件即为$d_i+d_j\leq r_i+r_j$,考虑枚举$j$,那么我们要查询有多少满足$d_i-r_i\leq r_j-d_j$的$i$,用平衡树维护即可

现在树是动态的,那么每次我们往点分树中加一个叶子,先更新答案再更新平衡树即可,每个点分树中的点存两棵平衡树,一棵存以这个点为dfs起点的$d_i-r_i$,另一棵存以(它父亲到它管辖范围的第一个点)为dfs起点的$d_i-r_i$,查询时容斥一下就可以了

但直接加叶子会造成点分树不平衡,所以这里用替罪羊树的思想重构,这样就能保证时间复杂度

实现起来还是需要一点技巧的,如果要重构点分树中的一个点$x$,那么在原树中dfs时只访问那些在点分树中比$x$深的点就对应着$x$的点分树子树了,平衡树使用旋转treap,重构时先内存回收,再排序后$O(n)$建treap,这样会快一些(好吧主要是我写的常数太大...)

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<algorithm>
  4. #include<assert.h>
  5. using namespace std;
  6. typedef long long ll;
  7. const int inf=2147483647;
  8. ll ans;
  9. int r[100010],*d,*r1,*r2,*sz,*df;
  10. namespace tree{
  11. int h[100010],nex[200010],to[200010],v[200010],M;
  12. void ins(int a,int b,int c){
  13. M++;
  14. to[M]=b;
  15. v[M]=c;
  16. nex[M]=h[a];
  17. h[a]=M;
  18. }
  19. int fa[100010][17],dep[100010],dis[100010];
  20. void add(int a,int b,int c){
  21. ins(a,b,c);
  22. ins(b,a,c);
  23. fa[b][0]=a;
  24. dep[b]=dep[a]+1;
  25. dis[b]=dis[a]+c;
  26. for(int i=1;i<17;i++)fa[b][i]=fa[fa[b][i-1]][i-1];
  27. }
  28. int lca(int x,int y){
  29. int i;
  30. if(dep[x]<dep[y])swap(x,y);
  31. for(i=16;i>=0;i--){
  32. if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
  33. }
  34. if(x==y)return x;
  35. for(i=16;i>=0;i--){
  36. if(fa[x][i]!=fa[y][i]){
  37. x=fa[x][i];
  38. y=fa[y][i];
  39. }
  40. }
  41. return fa[x][0];
  42. }
  43. int vis[100010],siz[100010],lim,C;
  44. #define ok vis[to[i]]!=C&&to[i]!=fa&&d[to[i]]>=lim
  45. void dfs1(int fa,int x){
  46. siz[x]=1;
  47. for(int i=h[x];i;i=nex[i]){
  48. if(ok){
  49. dfs1(x,to[i]);
  50. siz[x]+=siz[to[i]];
  51. }
  52. }
  53. }
  54. int mn,cn,n;
  55. void dfs2(int fa,int x){
  56. int i,k=0;
  57. for(i=h[x];i;i=nex[i]){
  58. if(ok){
  59. dfs2(x,to[i]);
  60. k=max(k,siz[to[i]]);
  61. }
  62. }
  63. k=max(k,n-siz[x]);
  64. if(k<mn){
  65. mn=k;
  66. cn=x;
  67. }
  68. }
  69. }
  70. int getdis(int x,int y){
  71. using namespace tree;
  72. return dis[x]+dis[y]-dis[lca(x,y)]*2;
  73. }
  74. namespace treap{
  75. int fa[4000010],ch[4000010][2],fix[4000010],s[4000010],v[4000010],st[4000010],tp,M;
  76. #define l(x) ch[x][0]
  77. #define r(x) ch[x][1]
  78. int node(int d){
  79. int x;
  80. if(tp){
  81. x=st[tp--];
  82. fa[x]=l(x)=r(x)=0;
  83. }else
  84. x=++M;
  85. fix[x]=rand();
  86. v[x]=d;
  87. s[x]=1;
  88. return x;
  89. }
  90. void pushup(int x){
  91. s[x]=s[l(x)]+s[r(x)]+1;
  92. }
  93. void rot(int x){
  94. int y,z,f,b;
  95. y=fa[x];
  96. z=fa[y];
  97. f=ch[y][0]==x;
  98. b=ch[x][f];
  99. fa[x]=z;
  100. fa[y]=x;
  101. if(b)fa[b]=y;
  102. ch[x][f]=y;
  103. ch[y][f^1]=b;
  104. if(ch[z][0]==y)ch[z][0]=x;
  105. if(ch[z][1]==y)ch[z][1]=x;
  106. pushup(y);
  107. pushup(x);
  108. }
  109. int insert(int&x,int d){
  110. if(x==0)return x=node(d);
  111. int k;
  112. if(d<=v[x]){
  113. k=insert(l(x),d);
  114. if(!fa[l(x)])fa[l(x)]=x;
  115. }else{
  116. k=insert(r(x),d);
  117. if(!fa[r(x)])fa[r(x)]=x;
  118. }
  119. pushup(x);
  120. return k;
  121. }
  122. void ins(int&x,int d){
  123. int k=insert(x,d);
  124. while(fa[k]&&fix[k]>fix[fa[k]])rot(k);
  125. while(fa[x])x=fa[x];
  126. }
  127. int query(int x,int d){
  128. if(x==0)return 0;
  129. if(d>=v[x])return s[l(x)]+1+query(r(x),d);
  130. return query(l(x),d);
  131. }
  132. void rec(int x){
  133. if(!x)return;
  134. st[++tp]=x;
  135. rec(l(x));
  136. rec(r(x));
  137. }
  138. int stk[100010],top;
  139. int build(int*p,int n){
  140. int x,las,i;
  141. sort(p+1,p+n+1);
  142. top=0;
  143. for(i=1;i<=n;i++){
  144. x=node(p[i]);
  145. las=0;
  146. while(top&&fix[stk[top]]<fix[x]){
  147. pushup(stk[top]);
  148. las=stk[top--];
  149. }
  150. if(top)r(stk[top])=x;
  151. l(x)=las;
  152. stk[++top]=x;
  153. }
  154. while(top)pushup(stk[top--]);
  155. return stk[1];
  156. }
  157. }
  158. void drec(int fa,int x){
  159. using namespace tree;
  160. using namespace treap;
  161. rec(r1[x]);
  162. r1[x]=0;
  163. rec(r2[x]);
  164. r2[x]=0;
  165. for(int i=h[x];i;i=nex[i]){
  166. if(to[i]!=fa&&d[to[i]]>=lim)drec(x,to[i]);
  167. }
  168. }
  169. int p[100010],N,u;
  170. void dfs3(int fa,int x){
  171. using namespace tree;
  172. p[++N]=getdis(x,u)-r[x];
  173. for(int i=h[x];i;i=nex[i]){
  174. if(ok)dfs3(x,to[i]);
  175. }
  176. }
  177. int solve(int fa,int x){
  178. using namespace tree;
  179. dfs1(0,x);
  180. mn=inf;
  181. n=siz[x];
  182. dfs2(0,x);
  183. if(fa){
  184. u=fa;
  185. N=0;
  186. dfs3(0,x);
  187. r2[cn]=treap::build(p,N);
  188. }
  189. x=cn;
  190. vis[x]=C;
  191. df[x]=fa;
  192. d[x]=d[fa]+1;
  193. u=x;
  194. N=0;
  195. dfs3(0,x);
  196. r1[x]=treap::build(p,N);
  197. sz[x]=1;
  198. for(int i=h[x];i;i=nex[i]){
  199. if(ok)sz[x]+=sz[solve(x,to[i])];
  200. }
  201. return x;
  202. }
  203. void rebuild(int fa,int x){
  204. using namespace tree;
  205. lim=d[x];
  206. drec(0,x);
  207. C++;
  208. solve(fa,x);
  209. }
  210. namespace dtree{
  211. const double al=.85;
  212. int fa[100010],rt1[100010],rt2[100010],siz[100010],dep[100010];
  213. //rt1:root=self,rt2:root=fa->self_area_1st
  214. void addnode(int x){
  215. fa[x]=tree::fa[x][0];
  216. dep[x]=dep[fa[x]]+1;
  217. int u,t;
  218. for(u=x;fa[u];u=fa[u]){
  219. t=getdis(x,fa[u]);
  220. ans+=treap::query(rt1[fa[u]],r[x]-t);
  221. ans-=treap::query(rt2[u],r[x]-t);
  222. }
  223. treap::ins(rt1[x],-r[x]);
  224. for(u=x;fa[u];u=fa[u]){
  225. t=getdis(x,fa[u]);
  226. treap::ins(rt1[fa[u]],t-r[x]);
  227. treap::ins(rt2[u],t-r[x]);
  228. }
  229. for(u=x;u;u=fa[u])siz[u]++;
  230. t=0;
  231. for(u=x;fa[u];u=fa[u]){
  232. if(siz[u]>al*siz[fa[u]])t=fa[u];
  233. }
  234. if(t)rebuild(fa[t],t);
  235. }
  236. }
  237. int main(){
  238. using namespace treap;
  239. using namespace dtree;
  240. srand(19260817);
  241. int n,i,a,c;
  242. d=dep;
  243. r1=rt1;
  244. r2=rt2;
  245. sz=siz;
  246. df=dtree::fa;
  247. scanf("%d%d",&a,&n);
  248. scanf("%d%d%d",&a,&c,r+1);
  249. ins(rt1[1],-r[1]);
  250. d[1]=1;
  251. sz[1]=1;
  252. puts("0");
  253. for(i=2;i<=n;i++){
  254. scanf("%d%d%d",&a,&c,r+i);
  255. a^=(ans%1000000000);
  256. tree::add(a,i,c);
  257. addnode(i);
  258. printf("%lld\n",ans);
  259. }
  260. }

[UOJ55]紫荆花之恋的更多相关文章

  1. bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400

    3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status] ...

  2. 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT

    [BZOJ3435][Wc2014]紫荆花之恋 Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从 ...

  3. BZOJ 3435: [Wc2014]紫荆花之恋

    二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 ...

  4. luogu P3920 [WC2014]紫荆花之恋

    LINK:紫荆花之恋 每次动态加入一个节点 统计 有多少个节点和当前节点的距离小于他们的权值和. 显然我们不能n^2暴力. 考虑一个简化版的问题 树已经给出 每次求某个节点和其他节点的贡献. 不难想到 ...

  5. 【WC2014】紫荆花之恋(替罪羊重构点分树 & 平衡树)

    Description 若带点权.边权的树上一对 \((u, v)\) 为 friend,那么需要满足 \(\text{dist}(u, v) \le r_u + r_v\),其中 \(r_x\) 为 ...

  6. BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

    https://www.lydsy.com/JudgeOnline/problem.php?id=3435 https://www.luogu.org/problemnew/show/P3920 ht ...

  7. 数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋

    [题目描述] 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这棵大树实际上是一个带权 ...

  8. [WC 2014]紫荆花之恋

    Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上 ...

  9. UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ55.html 题解 做法还是挺容易想到的. 但是写的话…… 首先这种题如果只要求一棵树中的满足条件的点数( ...

随机推荐

  1. clearcase command (linux 常用命令)

    http://publib.boulder.ibm.com/infocenter/cchelp/v7r0m0/index.jsp?topic=/com.ibm.rational.clearcase.h ...

  2. goreplay HTTP-HTTPS流量复制工具

    goreplay相比tcpcopy只能复制HTTP和HTTPS的流量 goreplay编译很麻烦,就直接使用编译好的版本 gor_0.10.1_x64.tar.gz 支持centos5,测试的是cen ...

  3. [How to]Cloudera manager 离线安装手册

    2016-01-1910:54:05  增加kafka 1.简介 本文介绍在离线环境下安装Cloudera manager和简单使用方法 2.环境 OS:CentOS 6.7 Cloudera man ...

  4. leetcode 之Gas Station(11)

    这题的思路很巧妙,用两个变量,一个变量衡量当前指针是否有效,一个衡量整个数组是否有解,需要好好体会. int gasStation(vector<int> &gas, vector ...

  5. redis使用教程

    一.redis 的安装 官方就是个坑:只说make一下即可用,确实可以用,我以为装好了,结果好多问题: 安装步骤:make =>  make test  => make install 1 ...

  6. linux命令(6):tar命令

    压缩方法:tar zcvf test.tar.gz test [表示把文件夹目录压缩成test.tar.gz文件保存] 解压方法:tar zxvf test.tar.gz –C /home [表示解压 ...

  7. jpa缓存导致无法查询到更新后的数据&android出现ANR的一个解决办法

    1. 向服务器更新记录后查询,始终查询不到更新后的信息 只能查到更新之前的,马上推断出是缓存的问题.网上搜索一番,将问题定位为jpa缓存,我们要设置jpa查询时不从缓存中取,直接从数据库中取,这样便能 ...

  8. 兼容python3的SSDB客户端

    SSDB.py import socket class SSDB_Response(object): def __init__(self, code='', data_or_message=None) ...

  9. GT-----如何做Android应用流量测试?

    1.如何判断一个应用的流量偏高? 如果看流量的绝对值看不出高低,那就找几个同类型的产品对比一下,如果完成同样的事物,被测应用比同类产品高很多,那就偏高了,可能有优化的空间. 2.如何找到有效的优化点? ...

  10. (翻译)Xamarin.Essentials: 移动应用的跨平台 API

    原文地址:https://blog.xamarin.com/xamarin-essentials-cross-platform-apis-mobile-apps/ 当使用 Xamarin 开发 IOS ...