题目链接
http://poj.org/problem?id=2777
解题思路
二进制压缩(不知道为啥叫这个名,尽管用到了二进制)
思路不是很好讲,但是你看代码就知道思路了,主要先看树结构体的定义,再看主函数,再看子函数。
理解了本题如何使用的二进制就好理解了。
AC代码
#include<cstdio> #include<algorithm> using namespace std; const int N=1e5+100; int L,T,O; struct TREE { int l,r,lazy,num;//lazy=1表示tree.l~tree.r颜色相同,lazy=0表示tree.l~tree.r颜色不同,num,用二进制表示区域内包含的颜色,比如num的二进制为10100,含义为此区域有第2种和第4种颜色。 }tree[N<<2]; int x,y,col,ans,tmp; char op; int lowbit(int i) { return i&(-i);//找最后一个1,会树状数组应该就会这个 } void Build(int i,int l,int r) { tree[i].l=l; tree[i].r=r; tree[i].lazy=1;//初始化为区域内颜色相同 tree[i].num=1<<1;//左移的位数就是第几种颜色 if(l==r) return ; int mid=(l+r)>>1; Build(i<<1,l,mid); Build(i<<1|1,mid+1,r); tree[i].num=tree[i<<1].num|tree[i<<1|1].num;//可有可无,表示大区间颜色的种数是由俩儿子按位或得到的,这也是用二进制的妙处 return ; } void PushDown(int i) { if(tree[i].lazy==0) return ;//相同颜色的区域才会进行psuhdown操作,不同颜色的区域直接return tree[i<<1].lazy=tree[i].lazy; tree[i<<1|1].lazy=tree[i].lazy;//传递lazy tree[i<<1].num=tree[i].num;//因为区域颜色相同,所以左右儿子的颜色也相同,因此,可以用父亲的num赋值儿子的num//感觉这里理解起来比较难 tree[i<<1|1].num=tree[i].num; tree[i].lazy=0;//归零,表示区域内不再是同一颜色了 return ; } void Update(int i,int l,int r,int c) { if(l<=tree[i].l && tree[i].r<=r) { tree[i].lazy=1; tree[i].num=1<<c; return ; } PushDown(i);//pushdown之后 才能进行染色操作 if(tree[i<<1].r>=l) Update(i<<1,l,r,c); if(tree[i<<1|1].l<=r) Update(i<<1|1,l,r,c); tree[i].num=tree[i<<1].num|tree[i<<1|1].num; return ; } int Query(int i,int l,int r) { if(l<=tree[i].l && tree[i].r<=r) return tree[i].num; if(tree[i].l>r || tree[i].r<l) return 0; PushDown(i); int ll=0,rr=0; if(tree[i<<1].r>=l) ll=Query(i<<1,l,r);//左儿子的颜色数 if(tree[i<<1|1].l<=r) rr=Query(i<<1|1,l,r);//右儿子的颜色数 return ll|rr;//与之前的按位或的意义相同 } int main() { scanf("%d%d%d",&L,&T,&O); Build(1,1,L); while(O--) { getchar();//不能少 scanf("%c",&op); if(op=='C') { scanf("%d%d%d",&x,&y,&col); if(x>y) swap(x,y);//绝对不能少!我服了 Update(1,x,y,col); } else if(op=='P') { scanf("%d%d",&x,&y); if(x>y) swap(x,y);//绝对不能少!我服了 tmp=Query(1,x,y);//得到的是二进制表示的染色结果(这么说其实不严谨,但不知道怎么表达更确切了) ans=0; while(tmp>0) { ans++; tmp-=lowbit(tmp);//统计有多少个1,即有多少种颜色 } printf("%d\n",ans); } } }