题目要求支持两个操作
C x y v 将区间[x,y]内木块全染成v色。
P x y 回答区间[x,y]中不同颜色的个数。
思路:
下放标记,然后进行状态压缩。
对,就是这样。
压缩的状态中表示当前段存在哪几种颜色。
最后询问操作返回的是一个压缩的值。
这个时候我们就要统计返回值的二进制中1的个数。
可以用以下代码快速解决。
while(x){
count++;
x = x&(x-1);
}
至于为什么?
不赘述。
下面帖代码,有问题留言。
#include<cstdio> #include<algorithm> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define N 1000009 using namespace std; int w[N<<2|1],add[N<<2|1]; void update(int rt){ //左子树与右子树合并 w[rt] = (w[rt<<1]|w[rt<<1|1]); } void build(int l,int r,int rt){ if(l == r){ w[rt] |= 1; //初始化为1 add[rt] = 0; return; } int m = (l+r)>>1; build(lson); build(rson); update(rt); } void color(int l,int r,int rt,int v){ w[rt] &= 0; w[rt] |= (1<<(v-1)); add[rt] = v; } void push_col(int l,int r,int rt){ if(add[rt]){ //0代表没有标记,否则是标记了,那么下放标记 int m = (l+r)>>1; color(lson,add[rt]); color(rson,add[rt]); add[rt] = 0; } } void modify(int l,int r,int rt,int nowl,int nowr,int v){ if(nowl <= l && r <= nowr){ color(l,r,rt,v); return; } push_col(l,r,rt); int m = (l+r)>>1; if(nowl <= m)modify(lson,nowl,nowr,v); if(m < nowr)modify(rson,nowl,nowr,v); update(rt); } int query(int l,int r,int rt,int nowl,int nowr){ if(nowl <= l && r <= nowr)return w[rt]; push_col(l,r,rt); int m = (l+r)>>1; long long ans = 0; if(nowl <= m) ans |= query(lson,nowl,nowr); //左边与右边要合并 if(m < nowr)ans |= query(rson,nowl,nowr); return ans; } int read(){ //读入优化 int x = 0; char ch = getchar(); while(ch < '0' || ch > '9')ch = getchar(); while(ch >= '0' && ch <= '9'){ x =x * 10 + ch -'0'; ch = getchar(); } return x; } int main(){ int n = read(),t = read(),m = read(); build(1,n,1); while(m--){ char cmd[2]; scanf("%s",cmd); if(cmd[0] == 'C'){ int x = read(),y = read(),v =read(); if(x > y)swap(x,y); modify(1,n,1,x,y,v); } else { int x = read(),y =read(); if(x > y)swap(x,y); int ans = query(1,n,1,x,y); int count = 0; while(ans){ //计算个数 count++; ans = ans&(ans-1); } printf("%d ",count); } } return 0; }