传送门
题面:
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 41256 | Accepted: 12474 |
Description
Input
Output
Sample Input
2 2 4 C 1 1 2 P 1 2 C 2 2 2 P 1 2
Sample Output
2 1
Source
题目大意:
给定长度为L的线段,有两种操作,一、将一段区间染色,二、统计一段区间的颜色种类。
解题:
看操作可以很明显地看出是线段树。看颜色数只有30种,可以用int表示状态,每一位表示颜色有无。两种颜色合并,可以采用位或操作,最后统计1的个数即可。
坑点:
1.a可能大于b
2.起始颜色是1
3.多样例
代码:
#include <iostream> #include <cstdio> using namespace std; struct SegTree{ int l,r,val,lazy; }ST[400005]; //建树操作 void build(int i,int le,int ri) { ST[i].l=le; ST[i].r=ri; ST[i].val=1; ST[i].lazy=0; if(le==ri)return; int mid=(ST[i].l+ST[i].r)>>1; build(i<<1,le,mid); build(i<<1|1,mid+1,ri); } //下放懒标记 void push_down(int i) { ST[i<<1].val=ST[i<<1|1].val=ST[i].val; ST[i<<1].lazy=ST[i<<1|1].lazy=ST[i].lazy; ST[i].lazy=0; } //向上更新 void push_up(int i) { ST[i].val=ST[i<<1].val|ST[i<<1|1].val; } //更新操作 void update(int i,int le,int ri,int v) { if(le==ST[i].l&&ri==ST[i].r) { ST[i].val=v; ST[i].lazy=v; return; } int mid=(ST[i].l+ST[i].r)>>1; if(ST[i].lazy) push_down(i); if(ri<=mid) update(i<<1,le,ri,v); else if(le>mid) update(i<<1|1,le,ri,v); else { update(i<<1,le,mid,v); update(i<<1|1,mid+1,ri,v); } push_up(i); } //查询操作 int query(int i,int le,int ri) { int mid=(ST[i].l+ST[i].r)>>1; if(ST[i].l==le&&ST[i].r==ri) return ST[i].val; if(ST[i].lazy) push_down(i); if(le>mid) return query(i<<1|1,le,ri); else if(ri<=mid) return query(i<<1,le,ri); else return query(i<<1,le,mid)|query(i<<1|1,mid+1,ri); } int main() { int L,T,O,a,b,v,ans,cnt; char oper; while(~scanf("%d%d%d",&L,&T,&O)){ build(1,1,L); for(int i=0;i<O;i++) { scanf(" %c%d%d",&oper,&a,&b); //确保b>a if(a>b) { a^=b; b^=a; a^=b; } if(oper=='C') { scanf("%d",&v); //使对应位为1 update(1,a,b,1<<(v-1)); } else { //统计1的个数 cnt=0; ans=query(1,a,b); while(ans) { if(ans&1) cnt++; ans>>=1; } printf("%d\n",cnt); } } } }