P1558 色板游戏

P1558 色板游戏

题目背景
阿宝上学了,今天老师拿来了一块很长的涂色板。

题目描述
色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格。并从左到右标记为1, 2, ... L。

现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:

"C A B C" 指在A到 B 号方格中涂上颜色 C。
"P A B" 指老师的提问:A到 B号方格中有几种颜色。
学校的颜料盒中一共有 T 种颜料。为简便起见,我们把他们标记为 1, 2, ... T. 开始时色板上原有的颜色就为1号色。 面对如此复杂的问题,阿宝向你求助,你能帮助他吗?

输入输出格式
输入格式:
第一行有3个整数 L (1 <= L <= 100000), T (1 <= T <= 30) 和 O (1 <= O <= 100000)。 在这里O表示事件数。
接下来 O 行, 每行以 "C A B C" 或 "P A B" 得形式表示所要做的事情(这里 A, B, C 为整数, 可能A> B,这样的话需要你交换A和B)

输出格式:
对于老师的提问,做出相应的回答。每行一个整数。



错误日志: 1.第一次交了暴力 \(30\) 颗线段树 \(MLE\) 2. 后面换了个思路却忘记了题目有坑(以粗体标出)


Solution

这里要说一下 \(bitset\) 这个宝贝了(快 \(noip\) 了, 多运用 \(STL\) 节省时间)
支持位数很大的二进制运算, 自带压缩, 运算较快
简单来说就是一个可以有很多位的状压利器

这题很明显线段树, 用了 \(bitset\) 做状态说明: 第 \(i\) 位 为 \(1\) 代表此区间有这个颜色, 为 \(0\) 则没有
上传更新时使用或运算, 表示取并集(bitset很大一用处就是取状态很多的并集, 十分方便)
这是满足分配律的

修改打懒标记记录区间颜色, 改区间状态直接把 \(bitset\) 赋值为 \(0\) 然后确定颜色位修改为 \(1\) 即可

附: \(bitset\) 用法

声明n位bitset : bitset<n> b;
全部赋值为0 : b.reset();
为1 : b.set();
对第i位操作 : b[i] = 1/0;
一个bitset里1的个数 : num = b.count();

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<bitset>
typedef long long LL;
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 100019;
int num, numc, na;
#define lid (id << 1)
#define rid (id << 1) | 1
struct seg_tree{
    int l, r;
    int lazy;
    bitset<39>b;
    }tree[maxn << 2];
void pushup(int id){
    tree[id].b = tree[lid].b | tree[rid].b;
    }
void pushdown(int id){
    if(tree[id].lazy){
        int c = tree[id].lazy;
        tree[lid].b.reset(), tree[rid].b.reset();
        tree[lid].b[c] = 1, tree[rid].b[c] = 1;
        tree[lid].lazy = tree[rid].lazy = c;
        tree[id].lazy = 0;
        }
    }
void build(int id, int l, int r){
    tree[id].l = l, tree[id].r = r;
    if(l == r){
        tree[id].b[1] = 1;
        return ;
        }
    int mid = (l + r) >> 1;
    build(lid, l, mid), build(rid, mid + 1, r);
    pushup(id);
    }
void update(int id, int val, int l, int r){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r){
        tree[id].b.reset();
        tree[id].b[val] = 1;
        tree[id].lazy = val;
        return ;
        }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)update(rid, val, l, r);
    else if(mid >= r)update(lid, val, l, r);
    else update(lid, val, l, mid), update(rid, val, mid + 1, r);
    pushup(id);
    }
bitset<39> query(int id, int l, int r){
    pushdown(id);
    if(tree[id].l == l && tree[id].r == r){
        return tree[id].b;
        }
    int mid = (tree[id].l + tree[id].r) >> 1;
    if(mid < l)return query(rid, l, r);
    else if(mid >= r)return query(lid, l, r);
    else return query(lid, l, mid) | query(rid, mid + 1, r);
    }
int main(){
    num = RD();numc = RD();na = RD();
    build(1, 1, num);
    char cmd;
    for(int i = 1;i <= na;i++){
        cin>>cmd;
        int l = RD(), r = RD();
        if(l > r)swap(l, r);
        if(cmd == 'C'){
            int x = RD();
            update(1, x, l, r);
            }
        else printf("%d\n", (int)query(1, l, r).count());
        }
    return 0;
    }

原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9504920.html

时间: 2024-10-12 20:33:52

P1558 色板游戏的相关文章

线段树(压位)luogu P1558色板游戏

题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L. 现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事: "C A B C" 指在A到 B 号方格中涂上颜色 C. "P A B" 指老师的提问:A到 B号方格中有几种颜色. 学校的颜料盒中一共有 T 种颜料.为简便起见,我们把他们标记为 1, 2, ... T. 开始时色板上原

Luogu P1558 色板游戏【线段树/状态压缩】By cellur925

题目传送门 今天非常想再看一遍霸王别姬想不进去题于是开始刷数据结构 注意到至多只有\(30\)种颜色,啊啊啊啊我一开始竟然想的不是状态压缩而是在线段树中存一个30大小的数组,这样每次更新的时候暴力循环一遍.hhhhh. 可能这样比较好想吧,但是比正解状态压缩一下不知道差到哪里去了:).开始还智障地把每次循环的次数开成30,那给出的色板数有什么用hh,这样是80分,改后AC. #include<cstdio> #include<algorithm> #define maxn 1000

Luogu P1558 色板游戏

闲扯 一道线段树好题裸题 顺便吐槽一下出题人的数据... 最开始没看到 \(A\) 可能大于 \(B\) ,结果 \(WA\) 了.. 题面 题面 Solution 看范围, \(T\leq30\) ,发现可以用二进制表示是否包含每一种颜料,接下来的事就好办了. 对于操作 \(1\) ,是一个区间覆盖,直接将 \(s\) 变成 \(1<<(C-1)\) ,表示这个区间现在只含有 \(C\) 这种颜料,懒标记换一下. 下放也是一样的操作. 向上统计的时候直接用左区间的 \(s\) 或上右区间的

P1558 色板游戏 线段树(区间修改,区间查询)

题意: 给n,m,k,n长度,k个操作,m种颜色 操作C:输入A,B,C,区间[A,B]变成C颜色,可能A>B,所以要确保A<B 操作P:输入A,B,区间[A,B]的颜色种类 思路: 因为颜色只有30种,可以用位运算,然后进行lazy标记 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define il inline 5 #define it register int 6 #de

AC日记——色板游戏 洛谷 P1558

色板游戏 思路: sb题: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 struct TreeNodeType { int l,r,dis,mid,flag; }; struct TreeNodeType tree[maxn<<2]; int n,m,T,bit[31]; inline void in(int &now) { char Cget=getchar();now=0;

色板游戏(洛谷 1558)

题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L.现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. "C A B C" 指在A到 B 号方格中涂上颜色 C.2. "P A B" 指老师的提问:A到 B号方格中有几种颜色.学校的颜料盒中一共有 T 种颜料.为简便起见,我们把他们标记为 1, 2, ... T. 开始时色板

洛谷1558 色板游戏 线段树

我先立个Flag 我,这几天,要过1W道线段树题. 题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L.现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. "C A B C" 指在A到 B 号方格中涂上颜色 C.2. "P A B" 指老师的提问:A到 B号方格中有几种颜色.学校的颜料盒中一共有 T 种颜料.为简便起见,我

luogu 1558 色板游戏

题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L. 现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事: "C A B C" 指在A到 B 号方格中涂上颜色 C. "P A B" 指老师的提问:A到 B号方格中有几种颜色. 学校的颜料盒中一共有 T 种颜料.为简便起见,我们把他们标记为 1, 2, ... T. 开始时色板上原

2018年6月4号(线段树(4))

今天想和大家一起了解下今天我刚写的一道题: P1558 色板游戏 题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, ... L.现在色板上只有一个颜色,老师告诉阿宝在色板上只能做两件事:1. "C A B C" 指在A到 B 号方格中涂上颜色 C.2. "P A B" 指老师的提问:A到 B号方格中有几种颜色.学校的颜料盒中一共有 T 种颜料.