题意
n个房间排成一排, 相邻房间之间有1道门,一部分的门上有锁,其余的门可以直接打开
告诉你有锁的门的这把锁的钥匙的位置,询问q次,问从S可否到达T
1≤n,p≤106,0≤m<n,1≤x,y,Si,Ti<n,保证x不重复1≤n,p≤106,0≤m<n,1≤x,y,Si,Ti<n,保证x不重复
分析
一种搞法就是,先每个点找到右端点,然后再找左端点,然后再左右分别拓展,(然后就可以拿到80分,这个想想就很优秀,因为只有一些进来这个拓展区间很多次才能卡掉)
考虑100分的做法, 发现区间的拓展具有单向性,其实可以拓扑来做
但是一种优美的解法,把所有点random_shufflerandom_shuffle一下来拓展,就行了
时间复杂度大概是O(nlogn)O(nlogn)的,想想也觉得很优秀
种子选19260818
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
inline int read()
{
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int l,r;}q[N];
int p[N]; int ml[N],mr[N],id[N]; int fa[N];
int Find(int x){return (fa[x]==x) ? fa[x] : fa[x] = Find(fa[x]);}
void extend(int i)
{
while(1)
{
bool bk = 0;
if(ml[i] <= id[ml[i]-1] && id[ml[i]-1] <= mr[i]){ml[i] = min(ml[i],ml[Find(ml[i]-1)]); mr[i] = max(mr[i],mr[Find(mr[i]-1)]); bk = 1;}
if(ml[i] <= id[mr[i]] && id[mr[i]] <= mr[i]){ml[i] = min(ml[i],ml[Find(ml[i]+1)]); mr[i] = max(mr[i],mr[Find(mr[i]+1)]); bk = 1;}
if(!bk) break;
}
}
int main()
{
srand(19260817);
int n = read(); int m = read(); int qq = read();
for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),id[q[i].l] = q[i].r;
for(int i=1;i<=n;i++) ml[i] = mr[i] = i;
for(int i=1;i<=n;i++) fa[i] = i;
for(int i=n-1;i>=1;i--) if(!id[i]) mr[i] = mr[i+1],fa[Find(i)] = Find(i+1);
for(int i=1;i<n;i++) if(!id[i]) ml[i+1] = ml[i];
for(int i=1;i<=n;i++) p[i] = i; random_shuffle(p+1,p+n+1);
for(int i=1;i<=n;i++) if(fa[p[i]] == p[i]) extend(p[i]);
while(qq--)
{
int x = read(); int y = read();
if(ml[Find(x)] <= y && y <= mr[Find(x)]) printf("YES\n");
else printf("NO\n");
}
// cout<<(double)(clock())<<endl;
return 0;
}