题意很简单了,对一个区间有两种操作:
1. "C A B C" Color the board from segment A to segment B with color C.
//A~B涂上颜色C
2. "P A B" Output the number of different colors painted between segment A and segment B (including).
//输出A~B间颜色的种类数
题目链接:http://poj.org/problem?id=2777
~~~~
注意到颜色的种类只有30种,由此想到用按位或来合并两个区间的颜色(用一个32位的int型,每一位对应一种颜色),
最后求解所得结果有多少个1就是所求的答案了。
剩下的就是线段树的成段更新了。
#include<cstdio> #include<algorithm> #include<cstring> #define lson rt<<1,s,m #define rson rt<<1|1,m+1,e #define N 111111 using namespace std; int tre[N<<2],vis[N<<2]; void pushup(int rt) { tre[rt]=(tre[rt<<1] | tre[rt<<1|1]); } void build(int rt,int s,int e) { tre[rt]=1; vis[rt]=0; if(s==e) return ; int m=(s+e)>>1; build(lson); build(rson); pushup(rt); } void pushdown(int rt) { if(vis[rt]) { vis[rt<<1]=vis[rt<<1|1]=vis[rt]; tre[rt<<1]=tre[rt<<1|1]=tre[rt]; vis[rt]=0; } } int query(int l,int r,int rt,int s,int e) { if(l==s && r==e) return tre[rt]; pushdown(rt); int m=(s+e)>>1; if(r<=m) return query(l,r,lson); else if(l>m) return query(l,r,rson); else return (query(l,m,lson) | query(m+1,r,rson)); } void update(int c,int l,int r,int rt,int s,int e) { if(l<=s && r>=e) { tre[rt]=c; vis[rt]=1; return ; } pushdown(rt); int m=(s+e)>>1; if(r<=m) update(c,l,r,lson); else if(l>m) update(c,l,r,rson); else { update(c,l,m,lson); update(c,m+1,r,rson); } pushup(rt); } int main() { int n,t,m; while(~scanf("%d%d%d",&n,&t,&m)) { build(1,1,n); while(m--) { char op[5]; int l,r,c; scanf("%s",op); if(op[0]=='C') { scanf("%d%d%d",&l,&r,&c); if(l>r) swap(l,r); //~~ update(1<<(c-1),l,r,1,1,n); } else { scanf("%d%d",&l,&r); if(l>r) swap(l,r); //~~ int k=query(l,r,1,1,n); int ans=0; do{ if(k&1) ans++; //求解有多少个1. }while(k>>=1); printf("%d\n",ans); } } } return 0; }
POJ 2777 Count Color (线段树+位运算)
时间: 2024-10-10 18:20:32