[bzoj5194][Usaco2018 Feb][线段树]Snow Boots

39 篇文章 0 订阅
15 篇文章 0 订阅

Description

到冬天了,这意味着下雪了!从农舍到牛棚的路上有N块地砖,方便起见编号为1…N,第i块地砖上积了fi英尺的雪 。在Farmer
John的农舍的地窖中,总共有B双靴子,编号为1…B。其中某些比另一些结实,某些比另一些轻便。具
体地说,第i双靴子能够让FJ在至多si英尺深的积雪中行走,能够让FJ每步至多前进di。Farmer John从1号地砖出
发,他必须到达N号地砖才能叫醒奶牛们。1号地砖在农舍的屋檐下,N号地砖在牛棚的屋檐下,所以这两块地砖都 没有积雪。帮助Farmer
John求出哪些靴子可以帮助他走完这段艰辛的路程。

Input

第一行包含两个空格分隔的整数N和B(1≤N,B≤10^5)。

第二行包含N个空格分隔的整数;第i个整数为fi,即i号地砖的积雪深度(0≤fi≤10^9)。输入保证f1=fN=0
下面B行,每行包含两个空格分隔的整数。第i+2行的第一个数为si,表示第i双靴子能够承受的最大积雪深度。
第i+2行的第二个数为di,表示第i双靴子的最大步长。输入保证0≤si≤10^9以及1≤di≤N-1

Output

输出包含N行

第i行包含一个整数:如果Farmer John能够穿着第i双靴子从1号地砖走到N号地砖,为1,否则为0

Sample Input

8 7

0 3 8 5 6 9 0 0

0 5

0 6

6 2

8 1

10 1

5 3

150 7

Sample Output

0

1

1

0

1

1

1

题解

考试模拟题。。
把靴子按深度排序,格子也按深度排
然后离线把格子一个一个加进去
如果当前的靴子的深度为5,那么格子深度<5的全部加入线段中
问题转化为维护最长一段没有加入的格子
然后直接线段树。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
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;
}
inline void write(int x)
{
    if(!x) return (void)puts("0");
    if(x<0) putchar('-'),x=-x;
    static short s[25],t;
    while(x) s[++t]=x%10,x/=10; 
    while(t) putchar('0'+s[t--]);
    putchar('\n');
}
struct ozy666
{
    int y,up,op;
}a[110000],b[110000];int n,m;
bool cmp(ozy666 n1,ozy666 n2){return n1.y<n2.y;}
struct node
{
    int lc,rc,l,r,mx;
    int lb,rb;//左边开始最长一段 右边开始最长一段 
}tr[210000];int trlen;
void bt(int l,int r)
{
    int now=++trlen;
    tr[now].l=l;tr[now].r=r;
    tr[now].mx=tr[now].lb=tr[now].rb=r-l+1;
    tr[now].lc=tr[now].rc=-1;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=trlen+1;bt(l,mid);
        tr[now].rc=trlen+1;bt(mid+1,r);
    }
}
void upd(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    tr[now].mx=max(tr[lc].mx,tr[rc].mx);
    tr[now].mx=max(tr[now].mx,tr[lc].rb+tr[rc].lb);
    tr[now].lb=tr[lc].lb;
    if(tr[lc].lb==tr[lc].r-tr[lc].l+1)tr[now].lb=tr[lc].lb+tr[rc].lb;
    tr[now].rb=tr[rc].rb;
    if(tr[rc].rb==tr[rc].r-tr[rc].l+1)tr[now].rb=tr[rc].rb+tr[lc].rb;
}
void change(int now,int p)
{
    if(tr[now].l==tr[now].r)
    {
        tr[now].mx=tr[now].lb=tr[now].rb=0;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(tr[now].l+tr[now].r)/2;
    if(p<=mid)change(lc,p);
    else change(rc,p);
    upd(now);
}
int answer[110000];
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)a[i].y=read(),a[i].op=i;
    for(int i=1;i<=m;i++)b[i].y=read(),b[i].up=read(),b[i].op=i;//保护 跳跃 
    sort(a+1,a+1+n,cmp);
    sort(b+1,b+1+m,cmp);
    bt(1,n);
    int LA;
    for(int i=1;i<=n;i++)
    {
        if(a[i].y>b[1].y){LA=i;break;}
        change(1,a[i].op);
    }
    if(tr[1].mx<b[1].up)answer[b[1].op]=1;
    else answer[b[1].op]=0;
    for(int i=2;i<=m;i++)
    {
        if(b[i].y==b[i-1].y)
        {
            if(tr[1].mx<b[i].up)answer[b[i].op]=1;
            else answer[b[i].op]=0;
        }
        else
        {
            for(int j=LA;j<=n;j++)
            {
                if(a[j].y>b[i].y){LA=j;break;}
                change(1,a[j].op);
            }
            if(tr[1].mx<b[i].up)answer[b[i].op]=1;
            else answer[b[i].op]=0;
        }
    }
    for(int i=1;i<=m;i++)write(answer[i]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值