[BZOJ5288][Hnoi2018] Game (violence + randomization)

portal


First we consider violent practices.
Consider preprocessing, at first consider the points where the adjacent doors are unlocked as a block (then the blocks can reach each other), and note the left and right endpoints. Determine whether the door locks on the left and right of the block are in this block or not. If there is, expand the block to the left and right, or exit.
However, if this is the case, in the worst case, that is, jumping left and right, then O ( N 2 ) of.
How to do it? We can find that enumerating points in order is very inefficient, because we will expand to the previous block. Then we can randomly expand one point at a time, then the amortized complexity is O ( l O g N ) , the total complexity is O ( N l O g N )


#include<cstdio>
#include<iostream>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<cmath> 
using namespace std;
const int INF=1e9;
const int N=1000010;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch>='0' && ch<='9'){x=x*10+ch-'0'; ch=getchar();} 
    return x*f;
}
int l[N],r[N];
int pos[N];
int rnd[N];
void pre(int x)
{
    while(1)
    {
        bool bk=false;
        //左边的门
        if(l[x]<=pos[l[x]-1] && pos[l[x]-1]<=r[x])
        { 
            l[x]=min(l[x],l[l[x]-1]);
            r[x]=max(r[x],r[l[x]-1]);
            bk=true;
        }
        if(l[x]<=pos[ r[x] ] && pos[ r[x] ]<=r[x])
        { 
            l[x]=min(l[x],l[r[x]+1]);
            r[x]=max(r[x],r[r[x]+1]);
            bk=true; 
        }
        if(bk==false) break;
    }
}
int main()
{
//  freopen("game.in","r",stdin);
//  freopen("game.out","w",stdout);
    int n=read(),m=read(),Q=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        pos[x]=y;
    }
    pos[0]=pos[n+1]=n+1;
    for(int i=1;i<=n;i++) l[i]=r[i]=i;;
    for(int i=2;i<=n;i++) if(!pos[i-1]) l[i]=l[i-1];
    for(int i=n-1;i>=1;i--) if(!pos[i]) r[i]=r[i+1];
    for(int i=1;i<=n;i++) rnd[i]=i; random_shuffle(rnd+1,rnd+n+1);
    for(int i=1;i<=n;i++) pre(rnd[i]);

    while(Q--)
    {
        int x=read(),y=read();
        if(l[x]<=y && y<=r[x]) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324735337&siteId=291194637