题目传送门

题目大意:给你一棵树,有三种操作,在两个点之间连一个传送门,拆毁一个已有的传送门,询问两个点之间的合法路径数量。一条合法路径满足 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. java 定位工具

    #查看JVM所有进程及启动类信息以及PID jps -mlvV #查看JVM运行各种状态信息,包括GC,类加载,堆内存信息,jit编译信息等jstat -gcutil <PID> (堆内存 ...

  2. 【转】Android进阶2之 阴影制作(Shadow)

    阴影制作:包括各种形状(矩形,圆形等等),以及文字等等都能设置阴影. 阴影制作是什么原理呢? 其实很简单,你需要设置阴影的东西被看作一个主层.然后在主层下面画一个阴影层. 阴影制作涉及到一个重要函数: ...

  3. Codesys——限定符的使用方法[来自Codesys的Help]

    Qualifier for actions in SFC In order to configure in which way the actions should be associated to ...

  4. Luogu4198 楼房重建

    https://zybuluo.com/ysner/note/1124880 题面 带修改的区间维护最大斜率. 题面 解析 用线段树区间维护斜率. 考虑如何向上合并. 左半段一定有贡献. 如果左半段的 ...

  5. bzoj2142 礼物——扩展卢卡斯定理

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2142 前几天学了扩展卢卡斯定理,今天来磕模板! 这道题式子挺好推的(连我都自己推出来了) , ...

  6. AAC的ADTS头文件信息介绍

    遵循:BY-SA 署名-相同方式共享 4.0协议   作者:谭东 时间:2016年10月28日 环境:Windows 7   ADTS是Audio Data Transport Stream的简称. ...

  7. JSP-Runoob:JSP 国际化

    ylbtech-JSP-Runoob:JSP 国际化 1.返回顶部 1. JSP 国际化 在开始前,需要解释几个重要的概念: 国际化(i18n):表明一个页面根据访问者的语言或国家来呈现不同的翻译版本 ...

  8. 36.面板Ext.Panel使用

    转自:https://www.cnblogs.com/linjiqin/archive/2011/06/22/2086620.html 面板Ext.Panel使用 概要 1.Ext.Panel概述 2 ...

  9. JVM-垃圾回收器

    目录 垃圾收集器 Serial收集器 Serial Old 收集器 ParNew 收集器 Parallel Scavenge 收集器 (并行清除) /'pærəlɛl/ /'skævɪndʒ/ Par ...

  10. linux 查看内存和cpu

    Linux查看CPU和内存使用情况 在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要.在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况.运行 ...