题目传送门:https://www.luogu.org/problemnew/show/P4436
题意:
有n扇门,存在于两点之间;每个门都有对应的一把钥匙,放在某一个固定的点上。有q个询问,每次询问能否从x点到y点。
思路:
从师兄那学到了一些神奇的方法,如随机化。
随机生成一个访问顺序,按照这个顺序爆搜一遍即可。
基本保证每一个点被访问的次数是一个常数,所以时间复杂度为O(nk)(k为每个点被访问的次数)=O(玄学)。
用a[i].x,a[i].y记录当前这个点
因为对于一个已被拓展的点,我们已经知道他可以访问到的最大的左右边界,直接取个min,max即可。
代码:
#include<cstdio>
#include<ctime>
#include<algorithm>
using namespace std;
int n,m,q;
int yaoshi[1000010],p[1000010];
struct node{int x,y;} a[1000010];
void work(int now)
{
while(1)
{
bool bz=false;
if(a[now].x<=yaoshi[a[now].x-1]&&yaoshi[a[now].x-1]<=a[now].y)
a[now].x=min(a[now].x,a[a[now].x-1].x),a[now].y=max(a[now].y,a[a[now].y-1].y),bz=true;
if(a[now].x<=yaoshi[a[now].y]&&yaoshi[a[now].y]<=a[now].y)
a[now].x=min(a[now].x,a[a[now].x+1].x),a[now].y=max(a[now].y,a[a[now].y+1].y),bz=true;
if(!bz) break;
}
}
int main()
{
int x,y;
srand(time(0));
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
yaoshi[x]=y;
}
for(int i=1;i<=n;i++)
a[i].x=a[i].y=i;
for(int i=1;i<n;i++)
if(!yaoshi[i]) a[i+1].x=a[i].x;
for(int i=n-1;i>=1;i--)
if(!yaoshi[i]) a[i].y=a[i+1].y;
for(int i=1;i<=n;i++)
p[i]=i;
random_shuffle(p+1,p+n+1);
for(int i=1;i<=n;i++)
work(p[i]);
for(int i=1;i<=q;i++)
{
scanf("%d %d",&x,&y);
printf(y<a[x].x||y>a[x].y?"NO\n":"YES\n");
}
}