BSOJ6388题解

看上去就很神秘。。。考虑建出图论模型。

我们将一张牌的两面 \(a,b\) 连一条边。

考虑一个连通块的意义是什么。

边是一张牌,容易发现,如果连通块是一棵树,那么选择一个根节点相当于可以打出除了根节点以外的所有牌。

如果连通块不是树,那么所有数都可以被打出。

容易发现,如果一个区间的一个子集全部都在一个连通块中,且这个连通块是一棵树,那么这个区间就寄了。

所以我们对每棵树维护两个值:所在连通块的最大值和最小值。

如果有一个区间被询问区间所包含,那么这个区间就寄了。

只需要做一个二维数点即可。CDQ和主席树都行。

实际上?

我们对于一对 \((mi,mx)\),我们令 \(a[mx]=mi\),然后做一个前缀 \(\max\),如果 \(l\leq a[r]\),那么就寄了,否则没有寄掉。

复杂度 \(O(n\alpha(n)+m)\)

#include<cstdio>
const int M=1e5+5;
int n,k,a[M],f[M],mx[M],mi[M],siz[M];bool vis[M];
inline int max(const int&a,const int&b){
	return a>b?a:b;
}
inline int min(const int&a,const int&b){
	return a>b?b:a;
}
inline int Find(const int&u){
	return f[u]==u?u:f[u]=Find(f[u]);
}
inline void Merge(int u,int v){
	if((u=Find(u))==(v=Find(v)))return vis[u]=true,void();
	if(siz[u]>siz[v])siz[f[v]=u]+=siz[v],mx[u]=max(mx[u],mx[v]),mi[u]=min(mi[u],mi[v]),vis[u]|=vis[v];
	else siz[f[u]=v]+=siz[u],mx[v]=max(mx[v],mx[u]),mi[v]=min(mi[v],mi[u]),vis[v]|=vis[u];
}
signed main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i)siz[f[i]=i]=1,mi[i]=mx[i]=i;
	for(int i=1;i<=k;++i){
		int u,v;scanf("%d%d",&u,&v);Merge(u,v);
	}
	for(int i=1;i<=n;++i)if(!vis[i]&&f[i]==i)a[mx[i]]=mi[i];
	for(int i=2;i<=n;++i)a[i]=max(a[i],a[i-1]);
	scanf("%d",&k);
	for(int i=1;i<=k;++i){
		int l,r;scanf("%d%d",&l,&r);
		printf(l<=a[r]?"No\n":"Yes\n");
	}
}
posted @ 2022-03-07 15:29  Prean  阅读(28)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};