题目传送门

题目大意:给你一棵树,有三种操作,在两个点之间连一个传送门,拆毁一个已有的传送门,询问两个点之间的合法路径数量。一条合法路径满足 1.经过且仅经过一个传送门 2.不经过起点终点简单路径上的任何一条边

这模型转化好神啊

首先把树拍成$dfs$序

问题是在树上,我们把$x,y$这条链拎出来摊平,那么链上每个点都挂了一些子树。

容易发现合法路径数=连接以$x,y$为根的子树的传送门数量

而无根树并没有“子树”这一概念,所以先随便挑一个根跑出来dfs序。

发现“子树”的$dfs$序一定是一个或两个连续的区间,我们分$x,y$是否为$lca$讨论一下就可以了

然后把问题放到二维坐标系上。

问题转化成,动态在一个二维平面内加入/删除一个点,以及查询矩形内点的数量

由于存在修改操作,需要再加上一维。那么整个问题变成了一个三维偏序问题。用$CDQ$分治+树状数组即可

  1. #include <cmath>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define N1 100005
  6. #define M1 500005
  7. #define ll long long
  8. #define uint unsigned int
  9. using namespace std;
  10.  
  11. template <typename _T> void read(_T &ret)
  12. {
  13. ret=; _T fh=; char c=getchar();
  14. while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
  15. while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
  16. ret=ret*fh;
  17. }
  18.  
  19. struct Edge{
  20. int to[N1*],nxt[N1*],head[N1],cte;
  21. void ae(int u,int v)
  22. { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
  23. }e;
  24.  
  25. int n;
  26.  
  27. namespace Tree{
  28. int dep[N1],fa[N1],ff[N1][],st[N1],ed[N1],ord[N1],cur;
  29. void dfs1(int x)
  30. {
  31. int j,v; ff[x][]=x; st[x]=++cur; ord[cur]=x;//sz[x]=1;
  32. for(j=e.head[x];j;j=e.nxt[j])
  33. {
  34. v=e.to[j]; if(v==fa[x]) continue;
  35. fa[v]=x; ff[v][]=x; dep[v]=dep[x]+;
  36. dfs1(v);
  37. }
  38. ed[x]=cur;
  39. }
  40. void init()
  41. {
  42. dep[]=; dfs1();
  43. int i,j;
  44. for(j=;j<=;j++)
  45. for(i=;i<=n;i++)
  46. ff[i][j]=ff[ ff[i][j-] ][j-];
  47. }
  48. int LCA(int x,int y)
  49. {
  50. int i,ans=;
  51. if(dep[x]<dep[y]) swap(x,y);
  52. for(i=;i>=;i--)
  53. if(dep[ff[x][i]]>=dep[y]) x=ff[x][i];
  54. if(x==y) return x;
  55. for(i=;i>=;i--)
  56. if(ff[x][i]==ff[y][i]) ans=ff[x][i];
  57. else x=ff[x][i], y=ff[y][i];
  58. return ans;
  59. }
  60. int LCB(int x,int D)
  61. {
  62. int i;
  63. for(i=;i>=;i--)
  64. if(dep[ff[x][i]]>=D) x=ff[x][i];
  65. return x;
  66. }
  67. };
  68.  
  69. struct BIT{
  70. int sum[N1];
  71. void upd(int x,int w)
  72. {
  73. if(!x) return; int i;
  74. for(i=x;i<=n;i+=(i&(-i)))
  75. sum[i]+=w;
  76. }
  77. int query(int x)
  78. {
  79. int ans=,i;
  80. for(i=x;i>;i-=(i&(-i)))
  81. ans+=sum[i];
  82. return ans;
  83. }
  84. void clr(int x)
  85. {
  86. int i;
  87. for(i=x;i<=n;i+=(i&(-i)))
  88. sum[i]=;
  89. }
  90. }bit;
  91.  
  92. struct OP{ int x,y,t,type,f; }op[M1],tmp[M1];
  93. int cmp2(OP &s1,OP &s2)
  94. {
  95. if(s1.x!=s2.x) return s1.x<s2.x;
  96. if(s1.y!=s2.y) return s1.y<s2.y;
  97. return s1.type<s2.type;
  98. }
  99. int ans[N1],que[M1],isquery[N1],tl;
  100.  
  101. void CDQ(int L,int R)
  102. {
  103. if(L==R) return;
  104. int M=(L+R)>>,i,j,cnt=;
  105. CDQ(L,M); CDQ(M+,R);
  106. for(i=L,j=M+;i<=M&&j<=R;)
  107. {
  108. if(cmp2(op[i],op[j])){
  109. if(!op[i].type) bit.upd(op[i].y,op[i].f), que[++tl]=op[i].y;
  110. tmp[++cnt]=op[i]; i++;
  111. }else{
  112. if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y);
  113. tmp[++cnt]=op[j]; j++;
  114. }
  115. }
  116. while(i<=M){ tmp[++cnt]=op[i]; i++; }
  117. while(j<=R){ tmp[++cnt]=op[j]; if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y); j++; }
  118. for(i=L;i<=R;i++) op[i]=tmp[i-L+];
  119. while(tl){ bit.clr(que[tl]); tl--; }
  120. }
  121.  
  122. int m,Q1,Q2;
  123. using Tree::st; using Tree::ed; using Tree::dep; using Tree::LCA; using Tree::LCB;
  124.  
  125. int main()
  126. {
  127. scanf("%d",&n);
  128. int i,j,x,y,z,F,q,fl;
  129. for(i=;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
  130. Tree::init();
  131. read(Q1);
  132. for(q=;q<=Q1;q++)
  133. {
  134. read(x); read(y);
  135. op[++m]=(OP){st[x],st[y],,,}; op[++m]=(OP){st[y],st[x],,,};
  136. }
  137. read(Q2);
  138. for(q=;q<=Q2;q++) {
  139.  
  140. read(fl); read(x); read(y);
  141. if(fl==){
  142. op[++m]=(OP){st[x],st[y],q,,}; op[++m]=(OP){st[y],st[x],q,,};
  143. }else if(fl==){
  144. op[++m]=(OP){st[x],st[y],q,,-}; op[++m]=(OP){st[y],st[x],q,,-};
  145. }else if(fl==){
  146. F=LCA(x,y); isquery[q]=;
  147. if(x==F||y==F){
  148. if(x==F) swap(x,y); z=LCB(x,dep[F]+);
  149. op[++m]=(OP){ed[x],st[z]-,q,,}; //op[++m]=(OP){ed[x],0,q,1,-1};
  150. op[++m]=(OP){st[x]-,st[z]-,q,,-}; //op[++m]=(OP){st[x]-1,0,q,1,1};
  151. op[++m]=(OP){ed[x],n,q,,}; op[++m]=(OP){ed[x],ed[z],q,,-};
  152. op[++m]=(OP){st[x]-,n,q,,-}; op[++m]=(OP){st[x]-,ed[z],q,,};
  153. }else{
  154. op[++m]=(OP){ed[x],ed[y],q,,}; op[++m]=(OP){ed[x],st[y]-,q,,-};
  155. op[++m]=(OP){st[x]-,ed[y],q,,-}; op[++m]=(OP){st[x]-,st[y]-,q,,};
  156. }
  157. }
  158.  
  159. }
  160.  
  161. CDQ(,m);
  162. for(i=;i<=Q2;i++) if(isquery[i])
  163. printf("%d\n",ans[i]);
  164. return ;
  165. }

BZOJ 4285 使者 (CDQ分治+dfs序)的更多相关文章

  1. 【bzoj4182】Shopping 树的点分治+dfs序+背包dp

    题目描述 给出一棵 $n$ 个点的树,每个点有物品重量 $w$ .体积 $c$ 和数目 $d$ .要求选出一个连通子图,使得总体积不超过背包容量 $m$ ,且总重量最大.求这个最大总重量. 输入 输入 ...

  2. [BZOJ 3456]城市规划(cdq分治+FFT)

    [BZOJ 3456]城市规划(cdq分治+FFT) 题面 求有标号n个点无向连通图数目. 分析 设\(f(i)\)表示\(i\)个点组成的无向连通图数量,\(g(i)\)表示\(i\)个点的图的数量 ...

  3. [BZOJ 2989]数列(CDQ 分治+曼哈顿距离与切比雪夫距离的转化)

    [BZOJ 2989]数列(CDQ 分治) 题面 给定一个长度为n的正整数数列a[i]. 定义2个位置的graze值为两者位置差与数值差的和,即graze(x,y)=|x-y|+|a[x]-a[y]| ...

  4. 【BZOJ4285】使者 cdq分治+扫描线+树状数组

    [BZOJ4285]使者 Description 公元 8192 年,人类进入星际大航海时代.在不懈的努力之下,人类占领了宇宙中的 n 个行星,并在这些行星之间修建了 n - 1 条星际航道,使得任意 ...

  5. bzoj 4237 稻草人 - CDQ分治 - 单调栈

    题目传送门 传送点I 传送点II 题目大意 平面上有$n$个点.问存在多少个矩形使得只有左下角和右上角有点. 考虑枚举左下角这个点.然后看一下是个什么情况: 嗯对,是个单调栈.但不可能暴力去求每个点右 ...

  6. bzoj 3262 陌上花开 - CDQ分治 - 树状数组

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  7. BZOJ 2141: 排队 [CDQ分治]

    题意: 交换序列中两个元素,求逆序对 做分块做到这道题...一看不是三维偏序嘛.... 作为不会树套树的蒟蒻就写CDQ分治吧.... 对时间分治...x排序...y树状数组... 交换拆成两个插入两个 ...

  8. BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  9. BZOJ - 2809 dispatching 主席树+dfs序

    在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的 ...

随机推荐

  1. mysql 存储引擎的选择你会吗?

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXExMzU1NTQxNDQ4/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  2. VIM学习笔记 比较文件(diff)

    比较 可以从命令行调用以下命令,来打开两个文件进行比较: vim -d file1 file2 如果已经打开了文件file1,那么可以在Vim中用以下命令,再打开另一个文件file2进行比较: :di ...

  3. &#39;IOKING&#39; TCP Transmission Server Engine (&#39;云猴&#39;&#169;TCP通讯server引擎)(预告版)

    关键词: IOKING IOCP TCP  Transmission Server Engine Lock Free Interlocked 云猴完毕portTCP通讯server引擎 无锁 原子锁( ...

  4. 金典 SQL笔记 SQL语句汇总

    SELECT * FROM (SELECT ROW_NUMBER() OVER ( ORDER BY id) AS rowN,FNumber, FName,FSalary ,Fage FROM dbo ...

  5. Error:全局变量不明白(using namespace std 与全局变量的冲突)

    在用递归写八皇后时,定义了一个全局变量count,结果出现故障例如以下:提示全局变量不明白. 最后发如今实现文件.cpp中.我使用了using  namespace std; 解决方法: 1.使用co ...

  6. luogu 1045 麦森数

    题目大意: 从文件中输入P(1000<P<3100000),计算2^P−1的位数和最后500位数字(用十进制高精度数表示) 思路: 一道高精度练习题 其中位数是一个结论 位数=[P*log ...

  7. openStack logo

  8. Reward(toposort)

    http://acm.hdu.edu.cn/showproblem.php?pid=2647 #include <stdio.h> #include <string.h> #i ...

  9. RAP接口文档的安装

    本机环境 系统:CentOS 6.7 64 位 MySQL 5.6 JDK 1.8 Tomcat 8 Redis 3.0.7 Rap 0.14.1 Rap 说明 官网:https://github.c ...

  10. BZOJ 5277 IQ题orz

    思路: 首先我们注意到,对一个序列按分割点分开以后分别冒泡其实就相当于对整个序列进行冒泡.每一个元素都会对复杂度贡献1,除非一个元素两边的分割点都出现了.因此我们可以完全忽略快排的递归过程.只需考虑每 ...