2017暑假集训 div1 线段树(1)

本文通过两个经典算法题目——POJ2528和ZOJ1610,介绍了离散化处理和区间覆盖问题的解决方案。针对POJ2528问题,文章详细解释了如何使用离散化技巧简化数据处理过程;而在ZOJ1610中,则重点讨论了如何通过模拟覆盖的方式统计不同颜色的连续子段数量。

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

POJ 2528

题意:铺海报,问最后能看到几种海报

做法:原来做过的题,也写过博客。然而离散化还是不太会啊,大神的的离散化太巧妙了!

for(int i=1;i<=m;++i)
        {
            scanf("%d%d",&x[i],&y[i]);
            hash[++cnt]=x[i];
            hash[++cnt]=y[i];
        }
        sort(hash+1,hash+1+cnt);

        int num=1;
        for(int i= 2;i<=cnt;++i)
        {
            if(hash[num]!=hash[i]) hash[++num]=hash[i];
        }
        for(int i=num; i>=0;--i)
        {
            if(hash[i]-hash[i-1]>1) hash[++num]=hash[i]-1;
        }
        sort(hash+1,hash+1+num);


二分:

int bsearch(int l,int r,int x)
{
    int m;
    while(l<=r)
    {
        int m=(l+r)>>1;
        if(hash[m]==x) return m;
        else if(hash[m]>x) r=m-1;
        else l=m+1;
    }
    return l;
}

ZOJ 1610

题意:每次将[L,R]端点覆盖,问最后每个颜色有多少个连续的子段(如果没有则不输出)

做法:模拟覆盖,最后统计的时候,每次记录一下前一个点的颜色即可

注意:这里的L,R都是端点,其实覆盖的是[L+1,R]这个大区间,其中每个节点表示长度为1的小区间

还有一个坑点:L,R范围不确定,直接上8000把

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define lson rt<<1,begin,mid
#define rson rt<<1|1,mid+1,end

using namespace std;
const int maxn=8000;
int tree[maxn*4 +5];
int ans[maxn*4 +5];
int pre;

void pushdown(int rt)
{
    if(tree[rt]!=-1)
    {
        tree[rt<<1] = tree[rt<<1|1] = tree[rt];
        tree[rt] = -1;
    }
}
void updata(int rt,int begin,int end,int l,int r,int x)
{
    if(begin>=l&&r>=end)
    {
        tree[rt] = x;
        return ;
    }
    pushdown(rt);
    int mid=(begin+end)>>1;
    if(mid>=l) updata(lson,l,r,x);
    if(r>mid) updata(rson,l,r,x);
}

void querry(int rt,int begin,int end)
{
    if(begin==end)
    {
        if(tree[rt]>=0&&tree[rt]!=pre)
        {
            ans[tree[rt]]++;
        }
        pre=tree[rt]; return;
    }
    pushdown(rt);
    int mid=(begin+end)>>1;
    querry(lson); querry(rson);
}

int main()
{
    int m;
    while(scanf("%d",&m)!=EOF)
    {
        memset(tree,-1,sizeof(tree));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=m;++i)
        {
           int a,b,c;
           scanf("%d%d%d",&a,&b,&c);
           if(b>a)updata(1,1,8000,a+1,b,c);
        }
        pre=-1;

        querry(1,1,8000);
        for(int i=0;i<=8000;++i)
        {
            if(ans[i])
            {
                printf("%d %d\n",i,ans[i]);
            }
        }
        printf("\n");
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值