caioj【1101】:统计颜色(模板题) 线段树(lazytag)+离散化

题目大意:

有L段线段(编号为1~L, (1 <= L <= 1 0000 0000 没错,就是1亿 )) ,一开始全部线段是颜色1。
有两种操作:
1、C A B tt :把第A至第B个线段染成第tt种颜色
2、P A B :询问第A至第B个线段有多少种不一样的颜色。
注意:
1、A有可能比B大。
2、颜色的编号<=50;



离散化

刚get的离散化,虽然没有用一对一的方式记录下来,但是用自带函数还是好接受的。
先贴一下方便看~~~(某位大佬的代码)


scanf("%s%d%d",wen,&li[i],&ri[i]);
lisan[tot++]=li[i];lisan[tot++]=ri[i];
//将所有端点放在一个数组里,无关乎匹配,因为将来用lower_bound
 sort(lisan,lisan+tot);
 /*一般离散化到这一步就结束了,但是有漏洞,因为我们把所涉及端点排列后直接以+1+1的形式一一映射,所以(例:[3,5]与[8,10])映射之后可能就是挨在一起的一段([1,2]与[3,4])解决方法就是:不连续的两段在离散化以后中间加一个点隔开。*/

//思想如上述,但是真的插入的时候,是不需要这样的,如下方式还可以避免因为存在重复点而重复插。
 int m=unique(lisan,lisan+tot)-lisan;
 //把冗余的放在后面,返回尾指针,注意,是尾指针,指向排列成unique数列后的下一位
 int t=m;
 for(int i=1;i<=t;i++)
    if(lisan[i]-lisan[i-1]>1)lisan[m++]=lisan[i-1]+1;//尾部插入间隔点
 sort(lisan,lisan+m);//将插入点放到对应位置。

lazytag

纯纯的lazy,唯一值得注意的是lazy不累加,所以每次下放就需要把儿子的颜色集合清空


bitset

就是按照集合的思想,结合计算机位运算,实现压状。太大了bitset< n >地方不够。详细看链接吧。
https://www.cnblogs.com/BaiYiShaoNian/p/4591167.html


完整来代码:


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<bitset>
const int MAX=500000;
using namespace std;
struct segtree
{
    int l,r,lazy;
    bitset<51>s;
    segtree(){lazy=0;s.reset();s[1]=1;}
}arr[MAX];
void build(int p,int l,int r)
{
    arr[p].l=l;
    arr[p].r=r;
    if(l==r)return ;
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
}
void down(int p)
{
    if(arr[p].lazy!=0)
    {
        int lz=arr[p].lazy;arr[p].lazy=0;
        int ls=p<<1,rs=p<<1|1;
        arr[ls].s.reset();arr[ls].s[lz]=1;arr[ls].lazy=lz;
        arr[rs].s.reset();arr[rs].s[lz]=1;arr[rs].lazy=lz;
    }
}
void upp(int p)
{
    arr[p].s=(arr[(p<<1)].s|arr[(p<<1|1)].s);
}
void insert(int p,int x,int y,int v)
{
    int l=arr[p].l,r=arr[p].r;
    if(x<=l&&r<=y)
    {
        arr[p].s.reset();
        arr[p].lazy=v;
        arr[p].s[v]=1;
        return ;
    }
    down(p);
    int mid=(l+r)>>1;
    if(x<=mid)insert(p<<1,x,y,v);
    if(mid<y)insert(p<<1|1,x,y,v);
    upp(p);
}
bitset<51>ans;
void query(int p,int x,int y)
{
    int l=arr[p].l,r=arr[p].r;
    if(x<=l&&r<=y)
    {
        ans=(ans|arr[p].s);
        return ;
    }
    down(p);
    int mid=(l+r)>>1;
    if(x<=mid)query(p<<1,x,y);
    if(mid<y)query(p<<1|1,x,y);
    upp(p);
}
int li[100500],ri[100500],qes[100500],lisan[201000];
int main()
{
    char wen[8];
    int n,q,tot=0;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%s%d%d",wen,&li[i],&ri[i]);
        lisan[tot++]=li[i];lisan[tot++]=ri[i];     
        if(wen[0]=='C'){scanf("%d",&qes[i]);}
        if(wen[0]=='P'){qes[i]=-1;}
    }

    sort(lisan,lisan+tot);
    int m=unique(lisan,lisan+tot)-lisan;
    int t=m;
    for(int i=1;i<=t;i++)
        if(lisan[i]-lisan[i-1]>1)lisan[m++]=lisan[i-1]+1;
    sort(lisan,lisan+m);

    build(1,1,m);
    for(int i=1;i<=q;i++)
    {
        ans.reset();//注意每一次的初始化
        int x=lower_bound(lisan,lisan+m,li[i])-lisan+1;
        int y=lower_bound(lisan,lisan+m,ri[i])-lisan+1;
    //返回值是指针
    //不+1是从0开始的:lisan-lisan=0;
        if(x>y)swap(x,y);//题有坑,不过养成好习惯。
        //printf("(%d,%d)->(%d,%d)\n",li[i],ri[i],x,y);
        if(qes[i]==(-1))
        {

            query(1,x,y);
            printf("%d\n",ans.count());//很方便的统计位1的方式。
        }
        else
        {
            insert(1,x,y,qes[i]);
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值