Mayor's posters POJ - 2528 线段树染色+特殊离散化

题目链接:https://vjudge.net/problem/POJ-2528#author=0
参考:https://blog.csdn.net/weixin_44077863/article/details/98037868
https://blog.csdn.net/baiyifeifei/article/details/81672170
题意:给区间染色,求最后能看到多少颜色。
思路:区间范围太大,需要离散化。
对于
1
3
1 10
1 3
6 10
正确答案是3,如果按照正常的离散化,或导致3和6连在一起从而少算一种。正确的离散化应该是对于所有边界,如果两个连续的边界的差大于1,就要再添加一个中间值。 但是加上后反而过不了了。
查询操作如果没有l==r的判断是会WA的,按理说应该是TLE或RE才对。
这道题因为颜色种类太多,不能压缩到一个数内,因此删除了pushup操作。sum=-1表示没有颜色或颜色有多种。sum!=-1表示该节点所表示的范围内颜色都是一样的。对于查询的pushdown是可以省略掉的,因为如果当前节点的sum等于-1,就不需要下传标记(因为已经下传过了),如果当前节点sum不等于-1,下传标记反而会多此一举。下传标记后必须将当前节点的sum置-1,否则会因为只更新当前节点表示区间的一部分而使当前节点的颜色不纯从而出错。比如1-4区间,先涂成1,现在想把2-4涂成2,修改到区间1-2时,如果下传标记后sum没有置-1,那么出现1-2是纯色的错误。

#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <cmath>
#include <set>
#include <fstream>
#include <list>
#include <stack>
#include <map>
using namespace std;
const int maxn=1e5+5;
int p[maxn],vis[maxn];
struct NODE
{
    int l,r;
    int lazy,sum;
    NODE()
    {
        l=r=lazy=sum=0;
    }
} a[maxn*4];
void build(int l,int r,int k)
{
    a[k].l=l;
    a[k].r=r;
    a[k].sum=-1;
    if(l==r)
    {
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
}
void pushdown(int k)
{
    if(a[k].l==a[k].r||a[k].sum==-1)
    {
        return ;
    }
    a[k*2].sum=a[k].sum;
    a[k*2+1].sum=a[k].sum;
    a[k].sum=-1;
}
void add(int l,int r,int L,int R,int k,int val)
{
    if(l>R||r<L)
        return ;
    if(l>=L&&r<=R)
    {
        a[k].sum=val;
        return ;
    }
    int mid=(l+r)/2;
    pushdown(k);
    add(l,mid,L,R,k*2,val);
    add(mid+1,r,L,R,k*2+1,val);
}
int ans;
void query(int l,int r,int L,int R,int k)
{
    if(l>R||r<L)
        return ;
   // pushdown(k);
    if(a[k].sum!=-1)
    {
        if(!vis[a[k].sum])
        {
            ans++;
            vis[a[k].sum]++;
        }
    }
    else if(l==r)
        return ;
    else
    {
        int mid=(l+r)/2;
        query(l,mid,L,R,k*2);
        query(mid+1,r,L,R,k*2+1);
    }
    return ;
}
vector <int> v;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(vis,0,sizeof(vis));
        ans=0;
        v.clear();
        int n;
        scanf("%d",&n);
        for(int i=0; i<2*n; i++)
        {
            scanf("%d",&p[i]);
            v.push_back(p[i]);
        }
       /* sort(v.begin(),v.end());   //正确的离散化
        for(int i=1; i<2*n; i++)
          {
            if(v[i]-v[i-1]>1)
                v.push_back(v[i-1]+1);
          }*/
        sort(v.begin(),v.end());
        unique(v.begin(),v.end());
        int maxx=-1;
        for(int i=0; i<2*n; i++)
        {
            p[i]=lower_bound(v.begin(),v.end(),p[i])-v.begin()+1;
            maxx=max(maxx,p[i]);
        }
        build(1,maxx,1);
        int cnt=1;
        for(int i=0; i<2*n; i+=2)
        {
            add(1,maxx,p[i],p[i+1],1,cnt++);
        }
        query(1,maxx,1,maxx,1);
        printf("%d\n",ans);
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值