POJ 2777 Count Color(线段树!!!)
http://poj.org/problem?id=2777
题意:给出一段区间 L ,T种颜色,O种操作(1 <= L <= 100000), T(1 <= T <= 30) , (1 <= O <= 100000). ,初始时颜色都是染第一种颜色,然后再修改一些区间的颜色,给出一段区间,问这段区间内有多少种颜色。
1 .线段树的一个很重要的部分就是节点存的内容,除了l,r,c外还有一个state(该段区间有多少种颜色),开始没state还超时了,加了一个剪枝勉强过,可是30种染色,用二进制存的话,效率很高,所以改成了二进制
2. 更新时的下传和上传,very重要
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #define nMAX 100100 using namespace std; struct Node { int l,r,c,state; }node[nMAX*4]; int L,T; void create(int l,int r,int u) { node[u].l=l,node[u].r=r,node[u].state=1,node[u].c=0;//初始化为0 if(l==r)return ; int mid=(l+r)/2; create(l,mid,2*u); create(mid+1,r,2*u+1); } void printColor(int l,int r,int c,int u) { if(node[u].l>=l&&node[u].r<=r) {node[u].c=c; node[u].state=1<<(c-1); return;} if(node[u].c)//下传 { node[2*u].c=node[u].c,node[2*u+1].c=node[u].c; node[2*u].state=node[u].state, node[2*u+1].state=node[u].state, node[u].c=0; } int mid=(node[u].l+node[u].r)/2; if(r<=mid) printColor(l,r,c,2*u); else if(l>mid) printColor(l,r,c,2*u+1); else { printColor(l,mid,c,2*u); printColor(mid+1,r,c,2*u+1); } node[u].state=node[2*u].state|node[2*u+1].state;//上传 } int calculate(int l,int r,int u) { if(node[u].l>=l&&node[u].r<=r) return node[u].state; if(node[u].c)//下传 { node[2*u].c=node[u].c, node[2*u+1].c=node[u].c; node[2*u].state=node[u].state, node[2*u+1].state=node[u].state, node[u].c=0; } int mid=(node[u].l+node[u].r)/2; if(r<=mid) {return calculate(l,r,2*u);} else if(l>mid) {return calculate(l,r,2*u+1);} else return calculate(l,mid,2*u)|calculate(mid+1,r,2*u+1); } int Binary(int u) { int ans=0; while(u>0) { if(u%2)ans++; u/=2; } return ans; } int main() { int i,j,k,O; char ch; while(~scanf("%d%d%d",&L,&T,&O)) { create(1,L,1); int cnt=1; while(O--) { getchar(); scanf("%c",&ch); if(ch=='C') { scanf("%d%d%d",&i,&j,&k); int t; if(i>j){t=i,i=j,j=t;} printColor(i,j,k,1); } else { scanf("%d%d",&i,&j); int t; if(i>j){t=i,i=j,j=t;} int ans=calculate(i,j,1); ans=Binary(ans); printf("%d\n",ans); } } } return 0; }