JZOJ 5658. 【HNOI2018D2T1】游戏

Description

Description

Input

Input

Output

Output

Sample Input/Output

Sample Input/Output
Sample Input/Output

Data Constraint

Data Constraint

Hint

Hint

Solution

  • 听说这题很暴力……

  • 这里给出一个理论复杂度 O(N2) 的算法。(事实上 O(N) 带大常数)

  • 对于一个点 i ,我们记录 l[i],r[i] 表示它最左最右能扩展到哪里。

  • 对于一个位置 i ,我们记录一个 f[i] ,表示点 i i+1 中间的门的位置,为 0 则没有门。

  • 初始值:l[i]=r[i]=i , f[x]=y

  • 如果两个点中间没有门,则它们能互相直接到达。

  • 即:若 f[i1]=0 ,则有: l[i]=l[i1] r[i] 同理。

  • 之后我们就开始暴力扩展 l[i],r[i]

  • 如果 l[i]f[l[i]1]r[i] ,说明 i 可以捡到钥匙并往左扩展,则:l[i]=l[l[i]1]

  • r[i] 也一样尝试往右扩展。

  • 若一整次尝试扩展都没有更新到,就说明已扩展完毕,可以退出了。

  • 最后对于一次询问 s,t ,若 l[s]tr[s] 即为“YES”,否则为“NO”。

Code

#include<cstdio>
#include<cctype>
using namespace std;
const int N=1e6+5;
int l[N],r[N],f[N];
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) X=(X<<1)+(X<<3)+(ch^48),ch=getchar();
    return w?-X:X;
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    int n=read(),m=read(),p=read();
    for(int i=1;i<=m;i++)
    {
        int x=read();
        f[x]=read();
    }
    for(int i=1;i<=n;i++) l[i]=r[i]=i;
    for(int i=2;i<=n;i++)
        if(!f[i-1]) l[i]=l[i-1];
    for(int i=n-1;i;i--)
        if(!f[i]) r[i]=r[i+1];
    while(true)
    {
        bool pd=false;
        for(int i=2;i<=n;i++)
            while(l[i]>1 && l[i]<=f[l[i]-1] && f[l[i]-1]<=r[i]) l[i]=l[l[i]-1],pd=true;
        for(int i=n-1;i;i--)
            while(r[i]<n && l[i]<=f[r[i]] && f[r[i]]<=r[i]) r[i]=r[r[i]+1],pd=true;
        if(!pd) break;
    }
    while(p--)
    {
        int s=read(),t=read();
        puts(l[s]<=t && t<=r[s]?"YES":"NO");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值