牛客题 - 统计颜色(线段树变种)

统计颜色

题目链接: 2018年湘潭大学程序设计竞赛 - 统计颜色


题意

n个桶按顺序排列,我们用1~n给桶标号。有两种操作:
1 l r c 区间[l,r]中的每个桶中都放入一个颜色为c的球 (1≤l,r ≤n,l≤r,0≤c≤60)
2 l r 查询区间[l,r]的桶中有多少种不同颜色的球 (1≤l,r ≤n,l≤r)


思路一(错误的)

这道题一看就是线段树嘛,我就开始了套模板之旅,我原本是想在tree中加一个maxall来统计总共不同的数量,但是,这在PushDown和PushUp中展现出了非常大的难度,所以我就在每个tree里面开了一个have数组,来记录有没有出现过,这么如此简单粗暴的方法当然不可能过,又T又超内存了


思路二

经过同伴提醒,我突然想到了long long类型的大小就是2的63次方,这下操作就会非常简单了,无论是add还是原来的数,只需要进行操作 ‘|’ 就行了….果然过了


代码 (long long)

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1

typedef long long ll;
const ll INF = (ll)0x3f3f3f3f;
const ll MAXN = (ll)1e5+2;

struct Node{
    ll kin;
    ll add;
}tree[MAXN*4];

void PushUp(ll rt) {
    tree[rt].kin = tree[rson].kin | tree[lson].kin;
}

void PushDown(ll rt){
    if (tree[rt].add){
        ll t = tree[rt].add;
        tree[lson].add |= t;
        tree[lson].kin |= t;
        tree[rson].add  |= t;
        tree[rson].kin |= t;
        tree[rt].add = 0;
    }
}

void Update(ll L,ll R,ll C,ll l,ll r,ll rt){
    if (L <= l && r <= R){
        tree[rt].kin |= C;
        tree[rt].add |= C;
        return ;
    }
    ll m = (l+r)>>1;
    PushDown(rt);
    if (L <= m) Update(L,R,C,l,m,lson);
    if (R >  m) Update(L,R,C,m+1,r,rson);
    PushUp(rt);
}

ll Query(ll L,ll R,ll l,ll r,ll rt){
    if (L <= l && r <= R){
        return tree[rt].kin;
    }
    ll m = (l+r)>>1;
    PushDown(rt);
    ll res = 0;
    if (L <= m)  res |= Query(L,R,l,m,lson);
    if (R >  m)  res |= Query(L,R,m+1,r,rson);
    return res;
}

int main()
{
    ll n,m;
    while (~scanf("%lld %lld",&n,&m)){
        mmm(tree,0);

        ll op,L,R,va;
        while (m --){
            scanf("%lld %lld %lld",&op,&L,&R);
            if (op == 1){
                scanf("%lld",&va);
                Update(L,R,(ll)1<<va,1,n,1);
            }else {
                ll ans = Query(L,R,1,n,1);

                ll ttt = 0;
                while (ans){
                    if (ans&1)ttt++;
                    ans >>= 1;
                }
                printf("%lld\n",ttt);
            }
        }
    }
}

思路三

在看别人代码时,好像突然看到了一些奇怪的东西——bitset (C++ bitset 常用函数及运算符),这个东西非常好用,消耗的空间大致为size/8吧,相同情况下的bool需要的内存是它的8倍,并且bitset还有大量的内置运算,非常好用的’|’和count吧,还能用memset()来清空呢。


代码(bitset)

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)(j);i <= (int)(k);i ++)
#define per(i,j,k) for(int i = (int)(j);i >= (int)(k);i --)
#define mmm(a,b)   memset(a,b,sizeof(a))
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1

typedef long long ll;
typedef bitset<63> bi;
const int INF = (int)0x3f3f3f3f;
const int MAXN = (int)1e5+2;

struct Node{
    bi kin; //像数组一样直接定义即可
    bi add;
}tree[MAXN<<2];

void PushUp(int rt) {
    tree[rt].kin = tree[rson].kin | tree[lson].kin; //可直接进行|运算
}

void PushDown(int rt){
    if (tree[rt].add.any()){ //只要有一个数为1就返回true
        bi t = tree[rt].add;
        tree[lson].add |= t;
        tree[lson].kin |= t;
        tree[rson].add |= t;
        tree[rson].kin |= t;
        tree[rt].add = 0;   //难以置信,可直接清零
    }
}

void Update(int L,int R,ll C,int l,int r,int rt){
    if (L <= l && r <= R){
        tree[rt].kin |= C;
        tree[rt].add |= C;
        return ;
    }
    int m = (l+r)>>1;
    PushDown(rt);
    if (L <= m) Update(L,R,C,l,m,lson);
    if (R >  m) Update(L,R,C,m+1,r,rson);
    PushUp(rt);
}

bi Query(int L,int R,int l,int r,int rt){
    if (L <= l && r <= R){
        return tree[rt].kin;
    }
    int m = (l+r)>>1;
    PushDown(rt);
    bi res = 0;
    if (L <= m)  res |= Query(L,R,l,m,lson);
    if (R >  m)  res |= Query(L,R,m+1,r,rson);
    return res;
}

int main()
{
    int n,m;
    while (~scanf("%d %d",&n,&m)){
        mmm(tree,0);    //可以用mmm直接清零

        int op,L,R,va;
        while (m --){
            scanf("%d %d %d",&op,&L,&R);
            if (op == 1){
                scanf("%d",&va);
                Update(L,R,(ll)1<<va,1,n,1);
            }else {
                bi ans = Query(L,R,1,n,1);

                printf("%d\n",ans.count());//返回其中一的数量
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41428565/article/details/80166613
今日推荐