bzoj5288: [Hnoi2018]游戏【拓扑排序】

传送门

解题思路:

每个点可到达的都是一个区间,考虑如何求出这个区间。
暴力拓展肯定是 O ( n 2 ) 的,看看有没有什么性质。

考虑一扇门,如果钥匙在左边,那么右边的永远到不了左边。但左边一旦可以到右边,就可以走到右边可走的所有范围,所以我们从左边向右边连一条边,反之同理。

然后我们按拓扑序处理。每次判断当前区间是否能向两边走,如果可以,就继续拓展,然后把这个区间的范围扩大(将已拓展的区间并入,直接跳到其边缘)。由于每个区间最多被并入2次(一次左边一次右边)所以复杂度是 O ( n )

#include<bits/stdc++.h>
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=1000005;
int n,m,Q,p[N],l[N],r[N],id[N];
int tot,first[N],nxt[N],to[N],du[N];
queue<int>q;
void add(int x,int y)
{
    nxt[++tot]=first[x],first[x]=tot,to[tot]=y,du[y]++;
}
void extend(int i)
{
    while(1)
    {
        int bz1=1,bz2=1;
        if(l[i]==1)bz1=0;
        if(r[i]==n)bz2=0;
        if(bz1)
        {
            if((!p[l[i]-1])||(p[l[i]-1]>=l[i]&&p[l[i]-1]<=r[i]))l[i]=l[id[l[i]-1]];
            else bz1=0;
        }
        if(bz2)
        {
            if((!p[r[i]])||(p[r[i]]>=l[i]&&p[r[i]]<=r[i]))r[i]=r[id[r[i]+1]];
            else bz2=0;
        }
        if(!bz1&&!bz2)break;
    }
}
void topsort()
{
    for(int i=1;i<=n;i++)if(id[i]==i&&!du[i])q.push(i);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        extend(u);
        for(int e=first[u];e;e=nxt[e])
            if(!(--du[to[e]]))q.push(to[e]);
    }
}
int main()
{
    //freopen("game.in","r",stdin);
    //freopen("game.out","w",stdout);
    int x,y;
    n=getint(),m=getint(),Q=getint();
    for(int i=1;i<=n;i++)id[i]=l[i]=r[i]=i;
    while(m--)x=getint(),p[x]=getint();
    for(int i=1;i<=n;i++)
    {
        if(!p[i])id[i+1]=id[i];
        else p[i]<=i?add(id[i+1],id[i]):add(id[i],id[i+1]);
    }
    for(int i=1;i<=n;i++)l[id[i]]=min(l[id[i]],l[i]),r[id[i]]=max(r[id[i]],r[i]);
    topsort();
    for(int i=1;i<=n;i++)l[i]=l[id[i]],r[i]=r[id[i]];
    while(Q--)
    {
        x=getint(),y=getint();
        y>=l[x]&&y<=r[x]?puts("YES"):puts("NO");
    }
    //for(int i=1;i<=n;i++)cout<<i<<":"<<l[i]<<' '<<r[i]<<'\n';
    return 0;
}


猜你喜欢

转载自blog.csdn.net/cdsszjj/article/details/80242889
今日推荐