「CF1464F 」My Beautiful Madness 题解 (数据结构与树上算法)
作者:互联网
题目简介
给定一颗大小为\(n(n\le2*10^5)\)的树,\(m(m\le2*10^5)\)次操作,维护一个初始为空的路径集合\(P\)。
定义树上一条路径的\(d\)邻居(一个点集)\(S\)为:\(x \in S\)当前仅当存在一个路径上的点\(y\)满足\(dis(x,y)\le d\)。
操作分为三种:
\(1.\)输入\(u,v\),在\(P\)中加入\(u\)到\(v\)的路径。
\(2.\)输入\(u,v\),删除\(P\)中一个\(u\)到\(v\)的路径。
(注意\(u\)到\(v\)的路径与\(v\)到\(u\)的路径是相同的,若有多个\(u\)到\(v\)的路径只删除一个)
\(3.\)输入\(d\),询问\(P\)中所有路径的\(d\)邻居交集是否为空,若不为空输出Yes,否则输出No。
分析
首先推敲一下这些点中有没有一个能被清晰表述出来。答案是有的,这个点是所有路径的 \(Lca\) 当中深度最深的那个点的 \(d\) 级祖先。所以我们干脆用一条路径的 \(Lca\) 来代替这一条路径。
证明很感性,设这个 \(Lca\) 为点 \(x\) ,如果有一条线段在比 \(p\) 还远的地方,那么它和 \(x\) 所代表的路径一定没有交点。
考虑树上差分,如果对于 \(p\) 和 \(p\) 的 \(d\) 级祖先 \(q\) ,树上路径 \(p\to q\) 被覆盖的次数不如路径总数,那么答案显然是 No 。因为存在有的路径到 \(p\) 的距离大于 \(d\) 。
再考虑 \(q\) 的子树直径。如果有两个 \(Lca\) 之间的距离大于 \(d\) ,那么这两条路径显然也不能相交。
这道题涉及的知识面有点广,我们来一一理一下:
-
首先要能求出树的 \(Lca\) 和 \(dfn\) 序;
-
利用
multiset
来记录路径及其 \(Lca\) 的深度; -
利用树状数组来维护树上差分。
-
利用线段树维护子树的直径。
这道题思维巧妙,涉猎面广,实现较复杂,不愧为 \(\mbox{CF}\) 3500
分的大佬题目。
#include<cstdio>
#include<iostream>
#include<set>
using namespace std;
namespace simpler{
template<class T>inline T smax(T fir){return fir;}
template<class T>inline T smin(T fir){return fir;}
template<class T,class ...Args>inline T smax(T fir,Args ...args){return max(fir,smax(args...));}
template<class T,class ...Args>inline T smin(T fir,Args ...args){return min(fir,smin(args...));}
inline bool isnum(char ch){return ch>='0'&&ch<='9';}
template<class T=int>
inline T read(){
T x(0);static char ch=getchar();
for(;!isnum(ch);ch=getchar());
for(; isnum(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
return x;
}
template<class T>
inline T& read(T& x){return x=read<T>();}
template<class T,class ...Args>
inline auto read(T& x,Args& ...args){return x=read<T>(),read(args...);}
}
using namespace simpler;
const int Maxn=2e5+5;
const int Inf=0x3f3f3f3f;
class adjacency_list{
private:
int nxt[Maxn<<1],val[Maxn<<1];
int h[Maxn];
int tot;
public:
inline void add(int x,int y){nxt[++tot]=h[x];val[tot]=y;h[x]=tot;}
inline int head(int x){return h[x];}
inline int next(int x){return nxt[x];}
inline int operator[](int x){return val[x];}
}atr;
int L[Maxn],R[Maxn],dfn;
int dep[Maxn];
int f[Maxn][22];
void dfs(int x,int fa){
L[x]=++dfn;
f[x][0]=fa;dep[x]=dep[fa]+1;
for(int i=1;i<=20;++i)f[x][i]=f[f[x][i-1]][i-1];
for(int i=atr.head(x);i;i=atr.next(i))
if(atr[i]!=fa)dfs(atr[i],x);
R[x]=dfn;
}
inline int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;~i;--i)
if(dep[f[x][i]]>=dep[y])x=f[x][i];
if(x==y)return x;
for(int i=20;~i;--i)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
inline int dis(int x,int y){
if(x==-1||y==-1)return -Inf;
int z=lca(x,y);
return dep[x]+dep[y]-(dep[z]<<1);
}
struct node{
int x,y,len;
node():x(-1),y(-1),len(-Inf){}
node(int a,int b,int c):x(a),y(b),len(c){}
friend bool operator<(node fir,node sec){return fir.len<sec.len;}
friend node operator+(node fir,node sec){
if(fir.x==-1)return sec;
if(sec.x==-1)return fir;
node a=node(fir.x,sec.x,dis(fir.x,sec.x));
node b=node(fir.x,sec.y,dis(fir.x,sec.y));
node c=node(fir.y,sec.x,dis(fir.y,sec.x));
node d=node(fir.y,sec.y,dis(fir.y,sec.y));
return smax(fir,sec,a,b,c,d);
}
};
class segtree{
private:
int l[Maxn<<2],r[Maxn<<2];
node val[Maxn<<2];
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
inline void pushup(int x){val[x]=val[ls(x)]+val[rs(x)];}
public:
void build(int L,int R,int x=1){
l[x]=L,r[x]=R;
if(L==R)return ;
int mid=L+R>>1;
build(L,mid,ls(x));
build(mid+1,R,rs(x));
}
void modify(int p,node d,int x=1){
if(l[x]==r[x]){val[x]=d;return ;}
int mid=l[x]+r[x]>>1;
modify(p,d,p<=mid?ls(x):rs(x));
pushup(x);
}
node query(int ql,int qr,int x=1){
if(ql<=l[x]&&r[x]<=qr)return val[x];
int mid=l[x]+r[x]>>1;
if(qr<=mid)return query(ql,qr,ls(x));
if(ql>mid) return query(ql,qr,rs(x));
return query(ql,qr,ls(x))+query(ql,qr,rs(x));
}
}seg;
class tree_array{
private:
int tr[Maxn];
inline int lowbit(int x){return x&-x;}
public:
inline void add(int x,int n,int d){
for(;x<=n;x+=lowbit(x))tr[x]+=d;
}
inline int ask(int x){
int res=0;
for(;x;x-=lowbit(x))res+=tr[x];
return res;
}
inline int ask(int l,int r){return ask(r)-ask(l-1);}
}c;
multiset<pair<int,int>>s;
int cnt[Maxn];
int getfa(int x,int k){
for(int i=0;i<=20;++i)
if((k>>i)&1){
if(f[x][i])x=f[x][i];
else return 1;
}
return x;
}
int main(){
int n,m;read(n,m);
for(int i=1;i<n;++i){
int x,y;read(x,y);
atr.add(x,y);
atr.add(y,x);
}
dfs(1,0);seg.build(1,n);
while(m--){
int opt=read();
if(opt==1){
int x,y;read(x,y);
int z=lca(x,y);
c.add(L[x],n,1);c.add(L[y],n,1);c.add(L[z],n,-1);
s.emplace(-dep[z],z);
if(!cnt[z])seg.modify(L[z],node(z,z,0));
++cnt[z];
}else if(opt==2){
int x,y;read(x,y);
int z=lca(x,y);
c.add(L[x],n,-1);c.add(L[y],n,-1);c.add(L[z],n,1);
s.erase(s.find({-dep[z],z}));
--cnt[z];
if(!cnt[z])seg.modify(L[z],node());
}else{
int d=read();
int x=getfa(s.begin()->second,d),y=getfa(x,d);
if(c.ask(L[y],R[y])!=s.size()){puts("No");continue;}
node res=seg.query(L[y],R[y]);
puts(dis(x,res.x)<=d&&dis(x,res.y)<=d?"Yes":"No");
}
}
return 0;
}
$$-----EOF-----$$
标签:Beautiful,fir,CF1464F,return,int,题解,路径,read,ch 来源: https://www.cnblogs.com/wintersunny/p/16522453.html