caioj【1101】:统计颜色(模板题) 线段树(lazytag)+离散化
2017-12-03 22:27
387 查看
题目大意
离散化
lazytag
bitset
有两种操作:
1、C A B tt :把第A至第B个线段染成第tt种颜色
2、P A B :询问第A至第B个线段有多少种不一样的颜色。
注意:
1、A有可能比B大。
2、颜色的编号<=50;
先贴一下方便看~~~(某位大佬的代码)
https://www.cnblogs.com/BaiYiShaoNian/p/4591167.html
完整来代码:
离散化
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; }
相关文章推荐
- BZoj 1036: [ZJOI2008]树的统计Count【树链剖分+线段树--模板题】
- hdu 5023(线段树区间染色,统计区间内颜色个数)
- POJ 1151 & HDU 1542 Atlantis(扫描线模板 线段树 离散化)
- [线段树练习4] 线段颜色条数 - 统计标记总数
- 线段树区间更新,区间统计+离散化 POJ 2528 Mayor's posters
- [POJ2777] 统计颜色 - 线段树
- 线段树区间更新,区间统计+离散化 POJ 2528 Mayor's posters
- cd 915E(离散化+线段树)(新线段树模板)
- cd 915E(离散化+线段树)(新线段树模板)
- HDU-1255 覆盖的面积(线段树扫描线模板+离散化+加点修改题)
- HDU 6070 (线段树)(统计颜色)
- 线段树染色模板,用于颜色较少的情况。 POJ 2777
- hdu 3642 求长方体的体积交 (线段树 +离散化+扫描线)(重点!模板!)
- http://acm.pku.edu.cn/JudgeOnline/problem?id=2528 成段更新,区间统计颜色的种类(离散化处理线段)
- NEFU 1215 统计序列和 (线段树模板题)
- Count the Colors 数颜色 离散化+线段树
- poj-----(2528)Mayor's posters(线段树区间更新及区间统计+离散化)
- 线段树(区间更新以及统计片段颜色)
- 线段树模板(poj3468)
- P1903 【模板】分块/带修改莫队(数颜色)