您的位置:首页 > 大数据 > 人工智能

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

2017-12-03 22:27 387 查看
题目大意

离散化

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: