赞
踩
解题思路
如果一张牌的两个数字分别为 x , y x , y x,y,我们将x和y连边,那么最终就会形成几堆连通块。
如果一个连通块是一棵树,那么选每一条边相对于可以选一个数字。
所以我们记录每一个连通块的边数、最大值和最小值,如果
m
a
x
−
m
i
n
≥
s
i
z
e
max−min≥size
max−min≥size,那么久不可能构成一个
m
i
n
∼
m
a
x
min∼max
min∼max的顺子,也就是所有包含
[
m
i
n
,
m
a
x
]
[min,max]
[min,max]的询问都不可以选择成功。
统计下所以不合理的区间,将取件按照左端点排序,设 l a s t [ i ] last[i] last[i]表示从i开始最多可以接到多少的顺子,那么从m 枚举到1,在每一个min≥i的区间内取最小的max,那么 l a s t [ i ] = m a x − 1 last[i]=max−1 last[i]=max−1。
代码
#include<cstdio> #include<iostream> #include<queue> #include<algorithm> #include<cstring> #include<cmath> #define ll long long using namespace std; int n,m,sum,T,x,y,fa[100010],minn[100010],maxn[100010],size[100010],last[100010]; struct c{ int l,r; }a[100010]; int find(int x) { if(fa[x]==x)return fa[x]; else return find(fa[x]); } bool cmp(c l,c r) { return l.l<r.l; } int main() { // freopen("yy.in","r",stdin); // freopen("yy.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) fa[i]=maxn[i]=minn[i]=i; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); int xx=find(x),yy=find(y); if(xx!=yy) { size[xx]+=size[yy]+1; fa[yy]=xx; minn[xx]=min(minn[xx],minn[yy]); maxn[xx]=max(maxn[xx],maxn[yy]); } else size[xx]++; } for(int i=n;i>0;i--) { if(fa[i]==i&&size[i]<=maxn[i]-minn[i]) { a[++sum].l=minn[i],a[sum].r=maxn[i]; } } sort(a+1,a+sum+1,cmp); int t=n; for(int i=n;i>0;i--) { for (;a[sum].l==i;sum--) t=min(t,a[sum].r-1); last[i]=t; } scanf("%d",&T); while(T--) { scanf("%d%d",&x,&y); if(last[x]>=y) printf("Yes\n"); else printf("No\n"); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。