BZOJ 3888: [Usaco2015 Jan]Stampede

本文介绍了一种使用线段树和离散化技术解决特定问题的方法。通过预处理每头牛到达和离开的时间,并利用离散化减少数据规模,最终采用线段树进行区间覆盖操作来统计不同牛的出现次数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树+离散

预处理出每头牛到FJ面前的时间和离开时间,离散后用线段树按时间覆盖,最后统计牛的编号数

注意从y大的开始先覆盖,还有给出的是牛的尾巴坐标,牛头是(x,y+1)。我因为这WA了好几次。。。

代码:

<span style="font-family:SimSun;font-size:14px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int tree[500000*2+10];
 
struct s
{
    int y,w;
}d[500000*2+10];
 
 
bool pd[500010];
int now,n,m,i,j,k,x,y,r1;
void insert(int x,int l,int r,int a,int b,int num)//线段树插入
{
    int mid=0;
    if (tree[x]!=num)
    {
        mid=(a+b)>>1;
        if(a==l&&b==r)tree[x]=num;
        else
        {
            if (tree[x]>=0)
            {
                tree[x*2]=tree[x];
                tree[x*2+1]=tree[x];
                tree[x]=-1;
            }
            if(r<=mid) insert(x*2,l,r,a,mid,num);
            else
            if(l>=mid) insert(x*2+1,l,r,mid,b,num);
            else
            {
                insert(x*2,l,mid,a,mid,num);
                insert(x*2+1,mid,r,mid,b,num);
            }
        }
    }
     
}
 
bool cmp1(s i,s j)
{
    if (i.w<j.w)return true;
    return false;
}
 
bool cmp2(s i,s j)
{
    if(i.y>j.y)return true;
    if(i.y==j.y)return i.w<j.w?true:false;
    return false;
}
void pan(int x)
{
    if(!tree[x])return;
    if(tree[x]==-1)
    {
        pan(x*2),pan(x*2+1);
        return;
    }
    pd[tree[x]]=true;
    return;
}
int count()//统计工作
{
    pan(1);
    int ans=0;
    for(int i=1;i<=n;++i)
    if(pd[i])++ans;
    return ans;
}
int main()
{
     
    scanf("%d",&n);
    m=0;
    memset(tree,0,sizeof(tree));
    memset(pd,false,sizeof(pd));
    for(i=1;i<=2*n+4;++i)
    {
        d[i].w=0;
        d[i].y=0;
    }
    for(i=1;i<=n;++i)
    {
        scanf("%d%d%d",&x,&y,&r1);
        if (y<0) continue;
        d[2*++m-1].w=(0-x-1)*r1;
        d[2*m].w=(0-x)*r1;
        d[2*m-1].y=y;
        d[2*m].y=y;
    }//离散开始
    sort(d+1,d+2*m+1,cmp1);//按时间从小到大排序
    now=1;
    for(i=2;i<=2*m;++i)
    {
        if (d[i].w==d[i-1].w)d[i-1].w=now;
        else
        {
            d[i-1].w=now++;
        }
    }
    d[2*m].w=now;//离散结束
    sort(d+1,d+2*m+1,cmp2);//按y坐标从大到小排序
    for(i=1;i<=m;++i)
    {
        insert(1,d[i*2-1].w,d[i*2].w,1,now,i);
    }
    printf("%d",count());
    return 0;
}</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值