b_vj_Count Color(线段树+二进制表示颜色)

有一条被划分为L个线段的绳子,有T种颜色可选,且会有两种操作 (1<=L<=100000),T(1<=T<=30):

  • 将绳子的区间[a,b]染成颜色c
  • 统计绳子区间[a,b]中不同的颜色的数量

思路:tag[k]标记结点k的颜色

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
const int N=100010;
int a[N<<3],tag[N<<3];
void down(int k) {
    if (tag[k]) { 
        a[k<<1]=a[k<<1|1]=tag[k<<1]=tag[k<<1|1]=tag[k];
        tag[k]=0;
    }
}
void up(int k) {
    a[k]=a[k<<1]|a[k<<1|1];
}
void update(int ql, int qr, int l, int r, int k, int c) {
    if (ql<=l && r<=qr) {
        a[k]=tag[k]=c;
        return;
    }
    down(k);
    int m=l+r>>1, ans=0;
    if (m>=ql) update(ql,qr,l,m,k<<1,c);
    if (m<qr)  update(ql,qr,m+1,r,k<<1|1,c);
    up(k);
}
int ask(int ql, int qr, int l, int r, int k) {
    if (ql<=l && r<=qr)
        return a[k];    
    down(k);
    int m=l+r>>1, st=0;
    if (m>=ql) st|=ask(ql,qr,l,m,k<<1);
    if (m<qr)  st|=ask(ql,qr,m+1,r,k<<1|1);
    return st;
}
int count_color(int mask) {
    int cnt=0;
    while (mask>0) {
        if (mask&1) cnt++;
        mask>>=1;
    }
    return cnt;
}
int main() {
    int n,m,T; scanf("%d %d %d",&n,&T,&m);
    for(int i=1; i<=4*n; i++) a[i]=1;
    memset(tag,0,sizeof(tag));
    while (m--) {
        getchar();
        char t; scanf("%c", &t);
        if (t=='C') {
            int l,r,c; scanf("%d %d %d",&l,&r,&c);
            if (l>r) swap(l,r);
            update(l,r,1,n,1,1<<(c-1));
        } else {
            int l,r; scanf("%d %d",&l,&r);
            if (l>r) swap(l,r);
            printf("%d
", count_color(ask(l,r,1,n,1)));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wdt1/p/13935541.html