题目传送门

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

    从github下载jsoncpp-master 在执行\jsoncpp-master\makefiles\msvc2010文件夹下jsoncpp.sln 会有3个项目 执行lib_json项目生成li ...

  2. GammaRay观察Qt程序的运行状况

    GammaRay是KDAB开发的Qt应用程序的软件内省工具.利用QObject内省机制,它允许您在运行时观察和操作应用程序.这既可以在工作站本地使用,也可以在嵌入式目标上远程使用. 通过扩充指令级调试 ...

  3. ios17--自定义控件2改进

    控制器: // // XMGViewController.h #import <UIKit/UIKit.h> @interface XMGViewController : UIViewCo ...

  4. WebView播放H5课件时,锁屏解锁后,页面重新绘制的问题

    难题描述:H5页面播放 ,锁屏,解锁后,重新加载了页面,三星不会出现(onpause onstop ,onresume),但在小米.魅族会调用 onpause onstop ondestroy,onr ...

  5. js如何获取某id的子标签

    思路:根据id获取父对象,然后使用childNodes获取所有子对象数组,关键代码: document.getElementById(div_id).childNodes;   // 子对象数组 实例 ...

  6. [POI 2007] Zap

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1101 [算法] 首先 , 问题可以转化为求GCD(x,y) = 1,x <= ...

  7. 【POJ 1723】 SOLDIERS

    [题目链接] http://poj.org/problem?id=1723 [算法] 中位数 [代码] #include <algorithm> #include <bitset&g ...

  8. bzoj 1078 [SCOI2008]斜堆 —— 斜堆

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1078 考察斜堆的性质: 一个点如果没有左子树,也一定没有右子树: 看了这篇精美的博客:htt ...

  9. 安装nghttp2 报错error: Libtool library used but 'LIBTOOL' is undefined

    nghttp2 报错error: Libtool library used but ‘LIBTOOL‘ is undefined 如果重新安装libtool和autoconf升级到2.69后,还是报错 ...

  10. ubuntu16.04 Flume 安装

    Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并 ...