【BZOJ3888】【Usaco2015 Jan】Stampede 线段树判区间覆盖

广告:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44066313");
}

题意:

PoPoQQQ 站在原点上向y轴正半轴看,然后有一群羊驼从他眼前飞过。这些羊驼初始都在第二象限,尾巴在(Xi,Yi),头在(Xi+1,Yi),每Ci秒向右走一个单位。
PoPoQQQ 能看见一匹羊驼当且仅当它身体任意某部位x坐标为0时,没有其它y坐标小于此羊驼的羊驼身体某部位x坐标为0。
PoPoQQQ 能看见几匹羊驼?

题解:

离散化一下看每头羊驼跨越y轴的时间左端点、右端点。
然后按y坐标排序后挨个去线段树里扫看是否被完全覆盖。

注意:

[3,4]以及[4,5]被覆盖不代表[4]被覆盖了
所以离散化时的取值略加修改。
WA if(i==1||lsh[i].x!=lsh[i-1].x)m++;
AC if(i==1||lsh[i].x!=lsh[i-1].x)m+=2;

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 50500
#define ls (note<<1)
#define rs (note<<1|1)
using namespace std;
struct LSH
{
    long long l,r,x;
    bool operator < (const LSH &a)const{return x<a.x;}
    LSH(long long _l=0,long long _r=0,long long _x=0):l(_l),r(_r),x(_x){}
}lsh[N*2],q[N];
int n,m,cnt;
struct Segment_Tree
{
    int l,r,c;
}s[N*6*4];
void pushup(int note)
{
    s[note].c=s[note].c|(s[ls].c&s[rs].c);
}
void build(int note,int l,int r)
{
    s[note].l=l,s[note].r=r;
    if(l==r)return ;
    int mid=l+r>>1;
    build(ls,l,mid),build(rs,mid+1,r);
}
int cover(int note,int l,int r)
{
    if(s[note].c)return 0;
    if(s[note].l==l&&r==s[note].r)
    {
        s[note].c=1;
        return 1;
    }
    int mid=s[note].l+s[note].r>>1,ret;
    if(r<=mid)ret=cover(ls,l,r);
    else if(l>mid)ret=cover(rs,l,r);
    else ret=(cover(ls,l,mid)|cover(rs,mid+1,r));
    pushup(note);
    return ret;
}
int main()
{
    freopen("test.in","r",stdin);
    int i,j,k;
    long long a,b,c;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        cin>>a>>b>>c;
        q[i].x=b,a=(-a-1)*c,c+=a;
        lsh[++cnt]=LSH(i,0,a);
        lsh[++cnt]=LSH(i,1,c);
    }
    sort(lsh+1,lsh+cnt+1);
    for(i=1;i<=cnt;i++)
    {
        if(i==1||lsh[i].x!=lsh[i-1].x)m+=2;
        if(lsh[i].r==0)q[lsh[i].l].l=m;
        else q[lsh[i].l].r=m;
    }
    sort(q+1,q+n+1);
    build(1,1,m);
    int ans=0;
    for(i=1;i<=n;i++)
    {
        ans+=cover(1,q[i].l,q[i].r);
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值