POJ2528 Mayor's posters 线段树+离散化

本文深入探讨了线段树在解决区间信息问题上的应用,通过具体实例讲解了如何利用离散化技巧和线段树进行高效区间查询与更新,特别关注于通过懒标记实现海报覆盖问题的解决方案。

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

果然我不会的题都是大佬眼里的水题。。我好菜啊啊啊55555...

先附上大佬博客Orz:https://blog.youkuaiyun.com/zezzezzez/article/details/80230026

                                   https://blog.youkuaiyun.com/u014779110/article/details/48784581

离散化其实看了大佬博客后就不难理解了,就是线段树QAQ...果然我还是没理解透彻啊。。。虽然是区间信息,但我怎么都不知道怎么用线段树555。。后来向某大佬请教Orz,突然明白了线段树存的是该位置当前由哪个海报占有,这个可以直接借助懒标记实现。查询操作只进行一次,当这个位置有海报(≠0)并且没出现过ans++,标记并return。

后来一直RE,一是因为数组开小了,二是因为线段树操作时r=toll不是n或tol(详见代码)

附上AC代码:(真不容易啊QAQ...)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
typedef pair<int,int>pp;
#define mkp make_pair
#define pb push_back
const double pi=acos(-1.0);
const double eps=1e-9;
const int INF=0x3f3f3f3f;
const ll MOD=1e9+7ll;

//数组开大一点,不然RE
const int MAX=5e4+10;
int n,m,ans;
struct node
{   int l,r,f;
}tree[8*MAX];
bool vis[2*MAX];
int zuo[MAX],you[MAX];
int tmp[2*MAX];

void build(int k,int l,int r) //建树
{
    tree[k].l=l,tree[k].r=r;
    tree[k].f=0;//tree[k].w=0;
    if(tree[k].l==tree[k].r)
    {   return; }
    int m=(tree[k].l+tree[k].r)>>1;
    build(k<<1,l,m);
    build(k<<1|1,m+1,r);
}
void down(int k)//标记下传
{
    tree[k<<1].f=tree[k].f;
    tree[k<<1|1].f=tree[k].f;
    //tree[k<<1].w=tree[k].f*(tree[k<<1].r-tree[k<<1].l+1);
    //tree[k<<1|1].w=tree[k].f*(tree[k<<1|1].r-tree[k<<1|1].l+1);
    tree[k].f=0;
}

void change_interval(int k,int a,int b,int y) //区间修改
{
    if(tree[k].l>=a&&tree[k].r<=b)
    {
        //tree[k].w=(tree[k].r-tree[k].l+1)*y;
        tree[k].f=y;//懒标记直接记录了该位置当前由哪个海报占有
        return;
    }
    if(tree[k].f)
        down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(a<=m)  change_interval(k<<1,a,b,y);
    if(b>m)  change_interval(k<<1|1,a,b,y);
}
void ask_interval(int k,int a,int b) //区间查询
{
    if(tree[k].f)//有海报
    {
        if(!vis[tree[k].f])//未出现过
        {
            ans++;
            vis[tree[k].f]=true;
        }
        return;
    }
    if(tree[k].l==tree[k].r)
        return;
    if(tree[k].f)  down(k);
    int m=(tree[k].l+tree[k].r)>>1;
    if(a<=m)  ask_interval(k<<1,a,b);
    if(b>m)  ask_interval(k<<1|1,a,b);
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        int x,y;
        scanf("%d",&n);
        memset(vis,false,sizeof(vis));

        //离散化
        memset(tmp,0,sizeof(tmp));
        int tol=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&zuo[i],&you[i]);
            tmp[++tol]=zuo[i];
            tmp[++tol]=you[i];
        }
        sort(tmp+1,tmp+1+tol);
        int toll=unique(tmp+1,tmp+1+tol)-tmp-1;
        int tt=toll;
        for(int i=2;i<=tt;i++)//注意此处循环!
        {
            if(tmp[i]-tmp[i-1]>1)
                tmp[++toll]=tmp[i-1]+1;
        }
        sort(tmp+1,tmp+1+toll);

        build(1,1,toll);//注意此处建树且为toll不是n!
        for(int i=1;i<=n;i++)
        {
            x=lower_bound(tmp+1,tmp+1+toll,zuo[i])-tmp;//注意为toll不是tol!
            y=lower_bound(tmp+1,tmp+1+toll,you[i])-tmp;
            //cout<<"x="<<x<<" y="<<y<<endl;
            change_interval(1,x,y,i);
        }
        ans=0;
        ask_interval(1,1,toll);//注意为toll不是n!
        printf("%d\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值