【牛客网】小w的魔术扑克

构造+离线+树状数组

有一道弱化版的题:【SCOI2010】连续攻击游戏

上面这道题,二分图最大匹配就可以了。当然这题也可以,传说中的\(n^3\)过1e5

不过,这还是好妙的一道题鸭!

part1.大致思路

首先,对于每张牌,在\(A[i]\)\(B[i]\)之间连一条无向边。

那么最后形成的图一定是由若干联通块组成的。

不难发现,如果联通块是一棵树,显然树上有一个值是取不到的。(自己手动模拟一下吧)。

因此,对于每个询问区间\([l,r]\),若\([l,r]\)中有若干个值,它们刚好构成了一棵树,那么肯定不能构成顺子\([l,r]\)

所以,我们只用判断区间\([l,r]\)中是否有若干个值构成一棵树即可。

part2.实现与流程

对于判断是否是一棵树,用并查集或者直接DFS都可以。

我们取出一棵树的最大点权Mx和最小点权Mi。不难发现,若一个区间只要包含了Mx和Mi,那么这个区间显然不能为顺子。

因此,我们可以想成:有若干条左端点为\(Mi[i]\),右端点为\(Mx[i]\)的约束线段,只要一个区间\([l,r]\)包含了至少一条约束线段,那么就是非法的。

把右端点排个序,离线+树状数组维护就可以了。

代码:

#include<bits/stdc++.h>
#define MAXN 100010
using namespace std;
int n,m,Q,A[MAXN],B[MAXN];
namespace p100{
	int cnt,head[MAXN],tot,BIT[MAXN];
	struct node{
		int ed,last;
	}G[MAXN<<2];
	bool vis[MAXN],can[MAXN];
	vector<int> S[MAXN];
	vector<node> P[MAXN];
	void DFS(int x,int fa,int &Mx,int &Mi,bool &is){
		vis[x]=true;
		Mx=max(Mx,x);
		Mi=min(Mi,x);
		for(int i=head[x];i;i=G[i].last){
			int t=G[i].ed;
			if(t==fa)continue;
			if(vis[t]){
				is=false;
				continue;
			}
			DFS(t,x,Mx,Mi,is);
		}
	}
	void Add(int st,int ed){
		tot++;
		G[tot]=node{ed,head[st]};
		head[st]=tot;
	}
	void ADD(int i,int x){
		while(i<=n)BIT[i]+=x,i+=i&-i;
	}
	int Query(int i){
		int res=0;
		while(i>=1)res+=BIT[i],i-=i&-i;
		return res;
	}
	void work(){
		for(int i=1;i<=m;i++){
			Add(A[i],B[i]);
			Add(B[i],A[i]);
		}
		for(int i=1;i<=n;i++){
			if(vis[i])continue;
			int Mx=0,Mi=2e9+7;
			bool is=true;
			DFS(i,0,Mx,Mi,is);
			if(is==true)S[Mx].push_back(Mi);
		}
		scanf("%d",&Q);
		for(int i=1;i<=Q;i++){
			int l,r;
			scanf("%d %d",&l,&r);
			P[r].push_back(node{l,i});
		}
		for(int i=1;i<=n;i++){
			for(int j=0;j<S[i].size();j++){
				int l=S[i][j];
				ADD(l,1);
			}
			for(int j=0;j<P[i].size();j++){
				int id=P[i][j].last,l=P[i][j].ed;
				if(Query(i)-Query(l-1)>=1)can[id]=false;
				else can[id]=true;
			}
		}
		for(int i=1;i<=Q;i++){
			if(can[i])puts("Yes");
			else puts("No");
		}
	}
}
int main() {
	scanf("%d %d",&n,&m);
	for(int i=1; i<=m; i++)scanf("%d %d",&A[i],&B[i]);
	p100::work();
	return 0;
}
posted @ 2019-10-30 11:24  TieT  阅读(171)  评论(0编辑  收藏  举报