题目链接:http://poj.org/problem?id=2777
题目大意:一个长为L的线段,两种操作:“C a b c”表示将区间[a,b]染成颜色c,“P a b”输出区间[a,b]内一共有多少种不同的颜色。
分析:很裸的线段树区间操作的题,注意到颜色种类一共不超过30种,我们可以把它对应到二进制中的每一位。
实现代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int M=1e5+10; struct segment { int l,r; int c; //表示该区间的染色 bool cov; //表示区间是否为纯色 int mid() { return (l+r)>>1; } }tree[M<<2]; void build(int rt,int l,int r) { tree[rt].l=l; tree[rt].r=r; tree[rt].c=1; tree[rt].cov=false; if(l==r) return ; int m=tree[rt].mid(); build(rt<<1,l,m); build(rt<<1|1,m+1,r); } void update(int rt,int l,int r,int c) { if(tree[rt].l==l&&tree[rt].r==r) { tree[rt].cov=false; tree[rt].c=(1<<(c-1)); return ; } if(!tree[rt].cov) { tree[rt<<1].c=tree[rt<<1|1].c=tree[rt].c; tree[rt].cov=true; tree[rt<<1].cov=tree[rt<<1|1].cov=false; } int m=tree[rt].mid(); if(r<=m) update(rt<<1,l,r,c); else if(l>m) update(rt<<1|1,l,r,c); else { update(rt<<1,l,m,c); update(rt<<1|1,m+1,r,c); } tree[rt].c=tree[rt<<1].c|tree[rt<<1|1].c; } int query(int rt,int l,int r) { if(!tree[rt].cov||(tree[rt].l==l&&tree[rt].r==r)) return tree[rt].c; int m=tree[rt].mid(); if(r<=m) return query(rt<<1,l,r); else if(l>m) return query(rt<<1|1,l,r); else return query(rt<<1,l,m)|query(rt<<1|1,m+1,r); } int count(int x) { int num=0; while(x) { x=x&(x-1); num++; } return num; } int main() { int n,t,op; while(scanf("%d%d%d",&n,&t,&op)!=-1) { build(1,1,n); while(op--) { char ch[5]; int a,b,c; scanf("%s",ch); if(ch[0]=='C') { scanf("%d%d%d",&a,&b,&c); if(a>b) swap(a,b); update(1,a,b,c); } else { scanf("%d%d",&a,&b); if(a>b) swap(a,b); int ans=query(1,a,b); printf("%d\n",count(ans)); } } } return 0; }