ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

「CF1464F 」My Beautiful Madness 题解 (数据结构与树上算法)

2022-07-26 20:05:36  阅读:137  来源: 互联网

标签:Beautiful fir CF1464F return int 题解 路径 read ch


题目简介

给定一颗大小为\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有