LibreOJ #2508.「HNOI2018」游戏 乱搞

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33229466/article/details/79963472

题意

这里写图片描述
n<=1000000

分析

在考场上打了nlogn炸的只剩50分。
正解还是比较巧妙的。
先把中间没有间隔的位置缩成一个点。若x到x+1的钥匙在x或x前面,则x+1必然不能到达x,反之则x必然不能到达x+1。
对于第一种情况,我们从x+1到x连一条边,反之则x到x+1连一条边。我们可以按照拓扑序来进行处理,对于每个点,不断地暴力往左边或右边跳。这样做复杂度看似是O(n^2),但每次跳一步可以看成是合并两个区间,所以实际上是O(n)的。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>

const int N=1000005;

int n,m,p,deg[N],L[N],R[N],tot,bel[N],sta[N],end[N],last[N],cnt,key[N],pos[N];
bool loc[N];
struct edge{int to,next;}e[N];
std::queue<int> que;

void addedge(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
}

void pre()
{
    for (int i=1;i<=tot;i++) if (!deg[i]) que.push(i);
    while (!que.empty())
    {
        int x=que.front();que.pop();
        while (1)
        {
            int flag=0;
            if (L[x]>1&&pos[L[x]-1]>=L[x]&&pos[L[x]-1]<=R[x]) L[x]=L[L[x]-1],flag=1;
            if (R[x]<tot&&pos[R[x]]>=L[x]&&pos[R[x]]<=R[x]) R[x]=R[R[x]+1],flag=1;
            if (!flag) break;
        }
        for (int i=last[x];i;i=e[i].next)
        {
            deg[e[i].to]--;
            if (!deg[e[i].to]) que.push(e[i].to);
        }
    }
}

int main()
{
    scanf("%d%d%d",&n,&m,&p);
    for (int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        loc[x]=1;key[x]=y;
    }
    loc[0]=1;
    for (int i=1;i<=n;i++)
    {
        if (loc[i-1]) tot++;
        bel[i]=tot;end[tot]=i;
        if (!sta[tot]) sta[tot]=i;
    }
    for (int i=1;i<tot;i++)
    {
        pos[i]=bel[key[end[i]]];
        if (pos[i]<=i) addedge(i+1,i),deg[i]++;
        else addedge(i,i+1),deg[i+1]++;
    }
    for (int i=1;i<=tot;i++) L[i]=R[i]=i;
    pre();
    while (p--)
    {
        int s,t;scanf("%d%d",&s,&t);
        if (L[bel[s]]<=bel[t]&&bel[t]<=R[bel[s]]) puts("YES");
        else puts("NO");
    }
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页