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

来源:互联网 发布:asp网站sql注入 编辑:程序博客网 时间:2024/06/06 03:47

  • 题目大意
  • 离散化
  • lazytag
  • bitset

题目大意:

有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;}