题目传送门

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

这模型转化好神啊

首先把树拍成$dfs$序

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

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

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

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

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

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

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

 #include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 100005
#define M1 500005
#define ll long long
#define uint unsigned int
using namespace std; template <typename _T> void read(_T &ret)
{
ret=; _T fh=; char c=getchar();
while(c<''||c>''){ if(c=='-') fh=-; c=getchar(); }
while(c>=''&&c<=''){ ret=ret*+c-''; c=getchar(); }
ret=ret*fh;
} struct Edge{
int to[N1*],nxt[N1*],head[N1],cte;
void ae(int u,int v)
{ cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
}e; int n; namespace Tree{
int dep[N1],fa[N1],ff[N1][],st[N1],ed[N1],ord[N1],cur;
void dfs1(int x)
{
int j,v; ff[x][]=x; st[x]=++cur; ord[cur]=x;//sz[x]=1;
for(j=e.head[x];j;j=e.nxt[j])
{
v=e.to[j]; if(v==fa[x]) continue;
fa[v]=x; ff[v][]=x; dep[v]=dep[x]+;
dfs1(v);
}
ed[x]=cur;
}
void init()
{
dep[]=; dfs1();
int i,j;
for(j=;j<=;j++)
for(i=;i<=n;i++)
ff[i][j]=ff[ ff[i][j-] ][j-];
}
int LCA(int x,int y)
{
int i,ans=;
if(dep[x]<dep[y]) swap(x,y);
for(i=;i>=;i--)
if(dep[ff[x][i]]>=dep[y]) x=ff[x][i];
if(x==y) return x;
for(i=;i>=;i--)
if(ff[x][i]==ff[y][i]) ans=ff[x][i];
else x=ff[x][i], y=ff[y][i];
return ans;
}
int LCB(int x,int D)
{
int i;
for(i=;i>=;i--)
if(dep[ff[x][i]]>=D) x=ff[x][i];
return x;
}
}; struct BIT{
int sum[N1];
void upd(int x,int w)
{
if(!x) return; int i;
for(i=x;i<=n;i+=(i&(-i)))
sum[i]+=w;
}
int query(int x)
{
int ans=,i;
for(i=x;i>;i-=(i&(-i)))
ans+=sum[i];
return ans;
}
void clr(int x)
{
int i;
for(i=x;i<=n;i+=(i&(-i)))
sum[i]=;
}
}bit; struct OP{ int x,y,t,type,f; }op[M1],tmp[M1];
int cmp2(OP &s1,OP &s2)
{
if(s1.x!=s2.x) return s1.x<s2.x;
if(s1.y!=s2.y) return s1.y<s2.y;
return s1.type<s2.type;
}
int ans[N1],que[M1],isquery[N1],tl; void CDQ(int L,int R)
{
if(L==R) return;
int M=(L+R)>>,i,j,cnt=;
CDQ(L,M); CDQ(M+,R);
for(i=L,j=M+;i<=M&&j<=R;)
{
if(cmp2(op[i],op[j])){
if(!op[i].type) bit.upd(op[i].y,op[i].f), que[++tl]=op[i].y;
tmp[++cnt]=op[i]; i++;
}else{
if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y);
tmp[++cnt]=op[j]; j++;
}
}
while(i<=M){ tmp[++cnt]=op[i]; i++; }
while(j<=R){ tmp[++cnt]=op[j]; if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y); j++; }
for(i=L;i<=R;i++) op[i]=tmp[i-L+];
while(tl){ bit.clr(que[tl]); tl--; }
} int m,Q1,Q2;
using Tree::st; using Tree::ed; using Tree::dep; using Tree::LCA; using Tree::LCB; int main()
{
scanf("%d",&n);
int i,j,x,y,z,F,q,fl;
for(i=;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x);
Tree::init();
read(Q1);
for(q=;q<=Q1;q++)
{
read(x); read(y);
op[++m]=(OP){st[x],st[y],,,}; op[++m]=(OP){st[y],st[x],,,};
}
read(Q2);
for(q=;q<=Q2;q++) { read(fl); read(x); read(y);
if(fl==){
op[++m]=(OP){st[x],st[y],q,,}; op[++m]=(OP){st[y],st[x],q,,};
}else if(fl==){
op[++m]=(OP){st[x],st[y],q,,-}; op[++m]=(OP){st[y],st[x],q,,-};
}else if(fl==){
F=LCA(x,y); isquery[q]=;
if(x==F||y==F){
if(x==F) swap(x,y); z=LCB(x,dep[F]+);
op[++m]=(OP){ed[x],st[z]-,q,,}; //op[++m]=(OP){ed[x],0,q,1,-1};
op[++m]=(OP){st[x]-,st[z]-,q,,-}; //op[++m]=(OP){st[x]-1,0,q,1,1};
op[++m]=(OP){ed[x],n,q,,}; op[++m]=(OP){ed[x],ed[z],q,,-};
op[++m]=(OP){st[x]-,n,q,,-}; op[++m]=(OP){st[x]-,ed[z],q,,};
}else{
op[++m]=(OP){ed[x],ed[y],q,,}; op[++m]=(OP){ed[x],st[y]-,q,,-};
op[++m]=(OP){st[x]-,ed[y],q,,-}; op[++m]=(OP){st[x]-,st[y]-,q,,};
}
} } CDQ(,m);
for(i=;i<=Q2;i++) if(isquery[i])
printf("%d\n",ans[i]);
return ;
}

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. poj 2955 Brackets dp简单题

    //poj 2955 //sep9 #include <iostream> using namespace std; char s[128]; int dp[128][128]; int ...

  2. 源代码编译安装MySQL5.6.12具体过程

    1 下载安装包download tar.gzwget http://download.csdn.net/detail/mchdba/7545037​2 安装cmake软件包yum install cm ...

  3. android 6.1解锁

    1.adb reboot bootloader 2.fastboot flashing unlock 3.power 键即可

  4. framework/base子目录

    framework/base下各子目录 ~/src/aosp_master/frameworks $ tree base/ -L 1 base/ ├── Android.bp ├── Android. ...

  5. win32 API函数

    cozy的博文 win32 API函数大全   (2008-03-15 16:28) 分类: 个人日记 1. API之网络函数 WNetAddConnection 创建同一个网络资源的永久性连接 WN ...

  6. UVA 1640(DFS)

    题意:给你a,b两个数 问你a b区间中0 9出现的次数 其实就是求1-n中0-9出现的次数 ans[n]   答案就是ans[b]-ans[a-1] 怎么求的话看代码吧 #include<io ...

  7. [算法基础]斐波那契(recursion+loop)两种方式执行时间对比

    一.斐波那契数列求第n项两种方式 1.递归(自上而下)def recur_fibonacci(n): if n <= 0: return 0 if n == 1: return 1 return ...

  8. [置顶] Snow的追寻

    题目描述 Snow终于得知母亲是谁,他现在要出发寻找母亲. 王国中的路由于某种特殊原因,成为了一棵有n个节点的根节点为1的树,但由于"Birds are everywhere.", ...

  9. javamail - 协议SMTP\IMAP\POP3设置

    资料来自:https://www.tutorialspoint.com/javamail_api/index.htm [SMTP - Simple Mail Transfer Protocol] Na ...

  10. 常用进制的转换、进制数的and与or或xor异或运算

    [十进制转换成其他进制]例:将25转换为二进制数 解: 25÷2=12 余数1  12÷2=6   余数0  6÷2=3     余数0  3÷2=1     余数1  1÷2=0     余数1 所 ...