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

题目传送门

今天非常想再看一遍霸王别姬想不进去题于是开始刷数据结构

注意到至多只有\(30\)种颜色,啊啊啊啊我一开始竟然想的不是状态压缩而是在线段树中存一个30大小的数组,这样每次更新的时候暴力循环一遍。hhhhh。

可能这样比较好想吧,但是比正解状态压缩一下不知道差到哪里去了:)。开始还智障地把每次循环的次数开成30,那给出的色板数有什么用hh,这样是80分,改后AC。

#include<cstdio>
#include<algorithm>
#define maxn 100090

using namespace std;

int n,Q,tot;
char op[10];
struct SegmentTree{
    int l,r;int lazy;
    int col[35];
}t[maxn*4];

void re(int &x)
{
    x=0;
    char ch=getchar();
    bool flag=false;
    while(ch<‘0‘||ch>‘9‘) flag|=(ch==‘-‘),ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    x=flag ? -x : x;
}

void build(int p,int l,int r)
{
    t[p].l=l,t[p].r=r;
    if(l==r)
    {
        t[p].col[1]=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    t[p].col[1]=t[p<<1].col[1]+t[p<<1|1].col[1];
}

void update(int p)
{
    if(!t[p].lazy||t[p].l==t[p].r) return ;
    t[p<<1].lazy=t[p].lazy;t[p<<1|1].lazy=t[p].lazy;
    for(int i=1;i<=tot;i++)
        t[p<<1].col[i]=0,t[p<<1|1].col[i]=0;
    t[p<<1].col[t[p].lazy]+=t[p<<1].r-t[p<<1].l+1;
    t[p<<1|1].col[t[p].lazy]+=t[p<<1|1].r-t[p<<1|1].l+1;
    t[p].lazy=0;
}

void change(int p,int l,int r,int id)
{
    update(p);
    if(t[p].l==l&&t[p].r==r)
    {
        for(int i=1;i<=tot;i++)
            t[p].col[i]=0;
        t[p].col[id]+=r-l+1;
        t[p].lazy=id;
        return ;
    }
    int mid=(t[p].l+t[p].r)>>1;
    if(l>mid) change(p<<1|1,l,r,id);
    else if(r<=mid) change(p<<1,l,r,id);
    else change(p<<1,l,mid,id),change(p<<1|1,mid+1,r,id);
    for(int i=1;i<=tot;i++)
        t[p].col[i]=t[p<<1].col[i]+t[p<<1|1].col[i];
}

int ask(int p,int l,int r,int id)
{
    update(p);
    if(t[p].l==l&&t[p].r==r) return t[p].col[id];
    int mid=(t[p].l+t[p].r)>>1;
    if(l>mid) return ask(p<<1|1,l,r,id);
    else if(r<=mid) return ask(p<<1,l,r,id);
    else return ask(p<<1,l,mid,id)+ask(p<<1|1,mid+1,r,id);
}

int main()
{
    scanf("%d%d%d",&n,&tot,&Q);
    build(1,1,n);
    while(Q--)
    {
        scanf("%s",op+1);
        if(op[1]==‘C‘)
        {
            int x=0,y=0,z=0;
            scanf("%d%d%d",&x,&y,&z);
            if(x>y) swap(x,y);
            change(1,x,y,z);
        }
        else if(op[1]==‘P‘)
        {
            int x=0,y=0;
            scanf("%d%d",&x,&y);
            if(x>y) swap(x,y);
            int cnt=0;
            for(int i=1;i<=tot;i++)
                if(ask(1,x,y,i)>0) cnt++;
            printf("%d\n",cnt);
        }
    }
    return 0;
}

最正确的做法是把每个节点的色板情况压成一个状态数,更新的时候用位运算更新==。这种方法我没有写,找了一个大佬写的:传送门

原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9901773.html

时间: 2024-11-09 20:50:04

Luogu P1558 色板游戏【线段树/状态压缩】By cellur925的相关文章

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

线段树(压位)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. 开始时色板上原

HDU 6183 Color it cdq分治 + 线段树 + 状态压缩

Color it Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Problem Description Do you like painting? Little D doesn't like painting, especially messy color paintings. Now Little B is painting. To prevent him from

洛谷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 种颜料.为简便起见,我

POJ P2777 Count Color——线段树状态压缩

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

POJ 2777 Count Color (线段树 + 状态压缩)

题目 Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the

Luogu P1558 色板游戏

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

P1558 色板游戏

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

HDU 4085 Peach Blossom Spring 斯坦纳树 状态压缩DP+SPFA

状态压缩dp+spfa解斯坦纳树 枚举子树的形态 dp[i][j] = min(dp[i][j], dp[i][k]+dp[i][l]) 其中k和l是对j的一个划分 按照边进行松弛 dp[i][j] = min(dp[i][j], dp[i'][j]+w[i][j])其中i和i'之间有边相连 #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn