题目链接:http://poj.org/problem?id=2777
题意:给出一面长度为len的墙,一开始的颜色是1,进行2种操作,一是将[l,r]涂成颜色p,二是询问[l,r]区间一共有多少种颜色
思路:对区间进行修改和询问,很容易想到用线段树,但是如何保存有多少种颜色呢,因为颜色少于30种(我又看了题解),所以可以用位运算进行状态压缩,剩下的就是线段树普通的区间修改和更新了(写题的时候花式出错,晚上太亢奋了吧……)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 100030 using namespace std; struct Tree { int l,r,date; }tree[maxn*3]; int lazy[maxn*3]; void build(int root,int l,int r) { tree[root].l=l; tree[root].r=r; if (l==r) { tree[root].date=(1<<1); return; } int mid=(l+r)>>1; build (root<<1,l,mid); build (root<<1|1,mid+1,r); tree[root].date=tree[root<<1].date|tree[root<<1|1].date; } void update(int root,int l,int r,int val) { if (tree[root].l>=l && tree[root].r<=r) { tree[root].date=(1<<val); lazy[root]=(1<<val); return; } if (lazy[root]!=0) { tree[root<<1].date=tree[root].date; tree[root<<1|1].date=tree[root].date; lazy[root<<1]=lazy[root]; lazy[root<<1|1]=lazy[root]; lazy[root]=0; } int mid=(tree[root].l+tree[root].r)>>1; if (l<=mid) update(root<<1,l,r,val); if (r>mid) update(root<<1|1,l,r,val); tree[root].date=tree[root<<1].date|tree[root<<1|1].date; } int que(int root,int l,int r) { if (lazy[root]!=0) return lazy[root]; if (tree[root].l==l && tree[root].r==r) return tree[root].date; int mid=(tree[root].l+tree[root].r)>>1; if (r<=mid) return que(root<<1,l,r); else if (l>mid) return que(root<<1|1,l,r); else return que(root<<1,l,mid)|que(root<<1|1,mid+1,r); } int main() { int len,n,m; while (scanf("%d%d%d",&len,&n,&m)!=EOF) { memset(lazy,0,sizeof(lazy)); build (1,1,len); for (int i=0;i<m;i++) { char tem; cin>>tem; if (tem=='C') { int a,b,p; scanf("%d%d%d",&a,&b,&p); if (a>b) swap(a,b); update(1,a,b,p); } else { int a,b,res=0,cl; scanf("%d%d",&a,&b); if (a>b) swap(a,b); cl=que(1,a,b); // cout<<":"<<cl<<endl; for (int i=1;i<=n;i++) { if ((cl&(1<<i))!=0) res++; } printf("%d\n",res); } } } }