【BZOJ5288】【HNOI2018】游戏(乱搞?)

232 篇文章 0 订阅
126 篇文章 3 订阅

题面

BZOJ
洛谷

题面自己到洛谷上看把

题解

考场上乱搞拿到了 90 分,简直不敢相信。
回家把代码再交了一份直接就 AC 了???

O(n2) 的做法应该很容易想
对于每个点作为起点,暴力向左右两侧拓展,
看看它能够到达的区间就行了。

考虑怎么优化一下,发现如果拓展的时候走到了一个已经拓展完的节点
那么一定能够到达这个点能够到达的左右位置
因此,直接沿着当前点能够到达的最远左右位置跳跃一下,
中间就不用计算了。

我们发现这样很容易卡成 O(n2)
于是我们倒着做,防止出题人故意卡正着做的
然后我就考场 90 分?洛谷/BZOJ AC了??

因为代码是考场代码,所以特别丑陋

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define RG register
#define MAX 1001000
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n,m,Q;
int L[MAX],R[MAX],K[MAX];
namespace Task1//20pts
{
    void Calc(int x)
    {
        int l=x,r=x,len=0;
        while(233)
        {
            len=r-l;
            while(l>1&&(!K[l-1]||(l<=K[l-1]&&K[l-1]<=r)))--l;
            while(r<n&&(!K[r]||(l<=K[r]&&K[r]<=r)))++r;
            if(r-l==len)break;
        }
        L[x]=l;R[x]=r;
    }
    void Solve()
    {
        for(int i=1;i<=n;++i)Calc(i);
        while(Q--)
        {
            int S=read(),T=read();
            if(L[S]<=T&&T<=R[S])puts("YES");
            else puts("NO");
        }
    }
}
namespace pf
{
    void Calc1(int x)
    {
        int l=x,r=x,len=0;
        while(233)
        {
            len=r-l;
            while(l>1&&(!K[l-1]||(l<=K[l-1]&&K[l-1]<=r)))r=max(r,L[l-1]),l=L[l-1];
            while(r<n&&(!K[r]||(l<=K[r]&&K[r]<=r)))++r;
            if(r-l==len)break;
        }
        L[x]=l;R[x]=r;
    }
    void Calc2(int x)
    {
        int l=x,r=x,len=0;
        while(233)
        {
            len=r-l;
            while(l>1&&(!K[l-1]||(l<=K[l-1]&&K[l-1]<=r)))
            {
                --l;
                //if(L[l])r=max(r,R[l]),l=L[l];
            }
            while(r<n&&(!K[r]||(l<=K[r]&&K[r]<=r)))l=min(l,R[r+1]),r=R[r+1];
            if(r-l==len)break;
        }
        L[x]=l;R[x]=r;
    }
    void Solve()
    {
        //for(int i=1;i<=n/2;++i)Calc1(i);
        for(int i=n;i>=1;--i)Calc2(i);
        while(Q--)
        {
            int S=read(),T=read();
            if(L[S]<=T&&T<=R[S])puts("YES");
            else puts("NO");
        }
    }
}

int main()
{
    //freopen("game.in","r",stdin);
    //freopen("game.out","w",stdout);
    n=read();m=read();Q=read();
    for(int i=1;i<=m;++i)
    {
        int x=read(),y=read();
        K[x]=y;
    }
    if(n<=1000)Task1::Solve();
    else pf::Solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值