(线段树统计区间种类)

第14届中北大学程序设计竞赛来了,集训队新买了一大堆气球,气球一共有K种颜色(1<=K<=256),气球的颜色从1-K编号。

ZBT童心未泯,他发明了一种摆放气球的游戏,规则如下。

       一排有N个桌子,每张桌子上只有一个气球插孔,即每张桌子最多只能放一个气球。编号分别为1-N(1<=N<=100000),每张桌子一开始是空的。现在对这张桌子要进行M次操作(1<=M<=100000),操作的种类一共有2种。

操作1:

操作指令格式: CHANGE L R C

       操作含义:在编号为L至编号为R的桌子分别放置颜色为C的气球(如果这些桌子上曾经有气球,则取下原来的气球。因为每张桌子上只能放置一个气球)

操作2:

操作指令格式: QUERY L R

       操作含义:输出编号为L到编号为R的桌子上的气球颜色种类数

现在他要求你写程序来完成他的操作,程序的输入输出见输入、输出描述

输入描述

第1行是三个整数N和M以及K,用空格隔开,分别代表桌子的个数、要进行操作指令的个数、以及气球的颜色总数。

接下来M行,每行一个操作指令,格式如上,保证指令中的1<=L<=R<=N, 1<=C<=K

 

输出描述

  如果操作指令中有查询操作(操作2),那么对于每个操作2输出一行,该行中只有一个整数即为该查询操作的答案。

  如果全部操作指令中都没有查询操作(操作2),那么请输出” This is a boring game!”(不含引号)

 

样例输入

10 20 5
QUERY 6 8
CHANGE 5 8 5
CHANGE 2 3 5
CHANGE 9 10 1
QUERY 9 9
QUERY 8 10
CHANGE 2 4 4
CHANGE 9 9 2
QUERY 2 2
CHANGE 8 10 1
CHANGE 6 9 3
CHANGE 10 10 2
QUERY 3 5
QUERY 6 8
QUERY 2 5
QUERY 5 5
QUERY 3 9
QUERY 4 10
CHANGE 5 8 1
QUERY 7 8

样例输出

0
1
2
1
2
1
2
1
3
4
1

题解:k 小的话,每个用二进制(1<<a[i])表示,由于k 比较大,所以每个节点用 bitset 表示

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<iomanip>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define pushup() tree[rt]=(tree[rt<<1],tree[rt<<1|1]);
#define nth(k,n) nth_element(a,a+k,a+n);  // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
#define Catalan C(2n,n)-C(2n,n-1)  (1,2,5,14,42,132,429...) // 卡特兰数
using namespace std;

inline int read(){
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;
const double pi = atan(1.)*4.;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int M=63;
const int N=1e5+5;
struct fun{
    bitset<270>bit;
}tree[N<<2],v[N<<2];



void sett(int l,int r,int rt){  // 建树
    if(l==r){
        tree[rt].bit=0;
        return ;
    }
    int mid=l+r>>1;
    sett(l,mid,rt<<1);
    sett(mid+1,r,rt<<1|1);
    tree[rt].bit=(tree[rt<<1].bit|tree[rt<<1|1].bit);
}

void fun(int l,int r,int rt){    // 下推
    if(v[rt].bit.count()){        // 统计 bit 中 1 的个数
        v[rt<<1].bit=v[rt].bit;
        v[rt<<1|1].bit=v[rt].bit;
        tree[rt<<1].bit=tree[rt].bit;
        tree[rt<<1|1].bit=tree[rt].bit;
        v[rt].bit=0;             // 记得清零
    }
}

void upset(int x,int y,int vel,int l,int r,int rt){
    if(x<=l&&y>=r){
        v[rt].bit.set(vel);
        tree[rt].bit=0;
        tree[rt].bit.set(vel);
        return ;
    }
    fun(l,r,rt);
    int mid=l+r>>1;
    if(x<=mid) upset(x,y,vel,l,mid,rt<<1);
    if(y>mid) upset(x,y,vel,mid+1,r,rt<<1|1);
    tree[rt].bit=(tree[rt<<1].bit|tree[rt<<1|1].bit);
}
bitset<270>bb(0);
void findd(int x,int y,int l,int r,int rt){
    if(x<=l&&y>=r){
        bb|=tree[rt].bit;
        return ;
    }

    fun(l,r,rt);
    int mid=l+r>>1;
    if(x<=mid)
        findd(x,y,l,mid,rt<<1);
    if(y>mid)
        findd(x,y,mid+1,r,rt<<1|1);
}
int main(){
    int n,m,k,a,b,c;
    scanf("%d %d %d",&n,&m,&k);
    sett(1,n,1);
    char s[20];
    getchar();
    int leap=0;
    while(m--){
        scanf(" %s",s);
        if(s[0]=='Q'){
            leap=1;
            scanf("%d %d",&a,&b);
            bb=0;
            findd(a,b,1,n,1);
            printf("%d\n",bb.count());
        }
        else{
            scanf("%d %d %d",&a,&b,&c);
            upset(a,b,c,1,n,1);
        }
    }
    if(!leap) printf("This is a boring game!\n");
    return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值