题目传送门

题目大意:给你一棵树,有三种操作,在两个点之间连一个传送门,拆毁一个已有的传送门,询问两个点之间的合法路径数量。一条合法路径满足 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=0; _T fh=1; char c=getchar();
 14     while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); }
 15     while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); }
 16     ret=ret*fh;
 17 }
 18
 19 struct Edge{
 20 int to[N1*2],nxt[N1*2],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][19],st[N1],ed[N1],ord[N1],cur;
 29 void dfs1(int x)
 30 {
 31     int j,v; ff[x][0]=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][1]=x; dep[v]=dep[x]+1;
 36         dfs1(v);
 37     }
 38     ed[x]=cur;
 39 }
 40 void init()
 41 {
 42     dep[1]=1; dfs1(1);
 43     int i,j;
 44     for(j=2;j<=18;j++)
 45     for(i=1;i<=n;i++)
 46         ff[i][j]=ff[ ff[i][j-1] ][j-1];
 47 }
 48 int LCA(int x,int y)
 49 {
 50     int i,ans=0;
 51     if(dep[x]<dep[y]) swap(x,y);
 52     for(i=18;i>=0;i--)
 53         if(dep[ff[x][i]]>=dep[y]) x=ff[x][i];
 54     if(x==y) return x;
 55     for(i=18;i>=0;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=18;i>=0;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=0,i;
 80     for(i=x;i>0;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]=0;
 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)>>1,i,j,cnt=0;
105     CDQ(L,M); CDQ(M+1,R);
106     for(i=L,j=M+1;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+1];
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=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
130     Tree::init();
131     read(Q1);
132     for(q=1;q<=Q1;q++)
133     {
134         read(x); read(y);
135         op[++m]=(OP){st[x],st[y],0,0,1}; op[++m]=(OP){st[y],st[x],0,0,1};
136     }
137     read(Q2);
138     for(q=1;q<=Q2;q++) {
139
140     read(fl); read(x); read(y);
141     if(fl==1){
142         op[++m]=(OP){st[x],st[y],q,0,1}; op[++m]=(OP){st[y],st[x],q,0,1};
143     }else if(fl==2){
144         op[++m]=(OP){st[x],st[y],q,0,-1}; op[++m]=(OP){st[y],st[x],q,0,-1};
145     }else if(fl==3){
146         F=LCA(x,y); isquery[q]=1;
147         if(x==F||y==F){
148             if(x==F) swap(x,y); z=LCB(x,dep[F]+1);
149             op[++m]=(OP){ed[x],st[z]-1,q,1,1};    //op[++m]=(OP){ed[x],0,q,1,-1};
150             op[++m]=(OP){st[x]-1,st[z]-1,q,1,-1}; //op[++m]=(OP){st[x]-1,0,q,1,1};
151             op[++m]=(OP){ed[x],n,q,1,1};    op[++m]=(OP){ed[x],ed[z],q,1,-1};
152             op[++m]=(OP){st[x]-1,n,q,1,-1}; op[++m]=(OP){st[x]-1,ed[z],q,1,1};
153         }else{
154             op[++m]=(OP){ed[x],ed[y],q,1,1};    op[++m]=(OP){ed[x],st[y]-1,q,1,-1};
155             op[++m]=(OP){st[x]-1,ed[y],q,1,-1}; op[++m]=(OP){st[x]-1,st[y]-1,q,1,1};
156         }
157     }
158
159     }
160
161     CDQ(1,m);
162     for(i=1;i<=Q2;i++) if(isquery[i])
163         printf("%d\n",ans[i]);
164     return 0;
165 }

转载于:https://www.cnblogs.com/guapisolo/p/10603729.html

BZOJ 4285 使者 (CDQ分治+dfs序)相关推荐

  1. 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries

    题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv​直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...

  2. BZOJ 4043 [HAOI2015]树上操作 dfs序 线段树

    $ \Rightarrow $ 戳我进BZOJ原题 $ \Rightarrow $ 戳我进洛谷原题 [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 25 ...

  3. bzoj 4237: 稻草人 cdq分治

    求有多少个点对  其一个点为左下角  一个点为右下角所形成的矩形内部没有点 每个x与y都不同 一开始的思路: 先按照x坐标排序  进行cdq分治 然后在cdq内对y进行排序  枚举mid+1-r的点作 ...

  4. bzoj 1176 Mokia (cdq分治)

    1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MB Submit: 3874  Solved: 1742 [Submit] ...

  5. [bzoj] 1176 Mokia || CDQ分治

    原题 给出W×W的矩阵(S没有用,题目有误),给出无限次操作,每次操作的含义为: 输入1:你需要把(x,y)(第x行第y列)的格子权值增加a 输入2:你需要求出以左下角为(x1,y1),右上角为(x2 ...

  6. BZOJ 3779 LCT 线段树 DFS序 坑

    hhhh抄了半天lty代码最后T了  对拍也没事.. 药丸 mine #pragma GCC optimize("O3") //By SiriusRen #include < ...

  7. BZOJ 1103: [POI2007]大都市meg [DFS序 树状数组]

    1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2221  Solved: 1179 [Submit][S ...

  8. bzoj 2141 : 排队 (cdq分治+bit)

    链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2141 思路: 其实就是求动态逆序对...cdq降维,用树状数组前后求两遍逆序对就好了 切水 ...

  9. cdq分治(bzoj 1176: [Balkan2007]Mokia bzoj 2683: 简单题)

    CDQ分治: 本质:对询问进行分治 优点:和莫队分块一样都属于技巧,关键时刻能免去复杂的数据结构,常数小 缺点:必须离线 参考:http://blog.csdn.net/hbhcy98/article ...

最新文章

  1. UA MATH565C 随机微分方程V Markov Family的算子
  2. ajax html xml数据格式,AJAX | 数据格式JSON与XML的区别
  3. 客观地认识程序员心中的恐惧
  4. react native 包学不包会系列--认识react native
  5. 用 ABAP 读取本地文本文件内容试读版
  6. 如何从零开始,成为element-plus的contributor
  7. Java实现XSS防御
  8. 将字符转换成带有圆圈的字符
  9. mysql5.5.35编译安装_CentOS 6.5最小化编译安装mysql 5.5.35
  10. 给硬盘分个整数大小的区
  11. php调用API支付接口 可个人使用,无需营业执照(使用第三方接口,调用的天工接口。)...
  12. MacW编辑部的电脑都装了哪些苹果应用?
  13. cannot connect to 192.168.137.137:5555: 由于目标计算机积极拒绝,无法连接。
  14. UE4 后期处理 PostProcess
  15. 送你一份2023Java学习路线,按图索骥,开启一路狂飙!
  16. 《百年孤独》马尔克斯
  17. c语言溢出进位,Z80上的溢出和进位标志
  18. 张钹院士:场景是当前AI产业化最大问题
  19. android中有米广告报错java.lang.NoClassDefFoundError: net.youmi.android.AdManager
  20. 物理学在计算机中的物理应用题,「试题研究」中考物理综合应用题的特点

热门文章

  1. python求矩阵维度必须一致_python数据分析(二)--Numpy
  2. 事业编还是程序员_头条员工为不加班,降薪去事业单位,结果蒙了:还不如当程序员...
  3. java中数组的返回值是什么类型_java基础学习:数组的常用操作与基础二维数组用法、及基本数据类型和引用数据类型赋值的区别...
  4. Upload LABS Pass-9
  5. redis集群实现(六) 容灾与宕机恢复
  6. 启蒙英语仍在培育期,DaDaBaby缘何能裂变式增长?
  7. quidway secpath下搭建DHCP服务器01
  8. iphone 如何成功的把three20成功的添加到xcode中去。
  9. Java开发实战经典 目录
  10. python判断一个数是否是质数