洛谷题单指南-线段树-P1558 色板游戏

原题链接:https://www.luogu.com.cn/problem/P1558

题意解读:给定序列a[n],初始都为1,支持两种操作:1.将区间[a,b]所有值都改为c;2.查询区间[a,b]范围有多少个不同的数;输出所有操作2的结果。

解题思路:又是线段树的典型应用,要支持区间修改,需要用到懒标记。

首先,本题中,颜色一共有1~30种,要表示最多30种颜色有无,只需要一个int整数即可,用二进制第i位是否为1表示是否有颜色i。

这样,线段树节点维护的信息就比较明朗:1.当前节点区间所有颜色all,2.懒标记color,表示所有子节点都应该设置成的颜色

struct Node
{
    int l, r;
    int all; //用二进制第i位是1表示包含颜色i
    int color; //懒标记,表示将所有子节点的颜色设置为color
} tr[N * 4];

pushup操作比较直观,直接对all进行或运算即可:

void pushup(Node &root, Node &left, Node &right)
{
    root.all = left.all | right.all;
}

void pushup(int u)
{
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

修改节点时,直接将all修改为要修改的颜色,然后打上懒标记即可:

void addtag(int u, int color)
{
    tr[u].all = (1 << color);
    tr[u].color = color;
}

将懒标记下传的操作也比较直观:

void pushdown(int u)
{
    if(tr[u].color)
    {
        addtag(u << 1, tr[u].color);
        addtag(u << 1 | 1, tr[u].color);
        tr[u].color = 0;
    }  
}

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;

struct Node
{
    int l, r;
    int all; //用二进制第i位是1表示包含颜色i
    int color; //懒标记,表示将所有子节点的颜色设置为color
} tr[N * 4];
int n, t, m;

void pushup(Node &root, Node &left, Node &right)
{
    root.all = left.all | right.all;
}

void pushup(int u)
{
    pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}

void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if(l == r) tr[u].all = (1 << 1); //初始都是颜色1
    else
    {
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void addtag(int u, int color)
{
    tr[u].all = (1 << color);
    tr[u].color = color;
}

void pushdown(int u)
{
    if(tr[u].color)
    {
        addtag(u << 1, tr[u].color);
        addtag(u << 1 | 1, tr[u].color);
        tr[u].color = 0;
    }  
}

void update(int u, int l, int r, int color)
{
    if(tr[u].l >= l && tr[u].r <= r) addtag(u, color);
    else if(tr[u].l > r || tr[u].r < l) return;
    else
    {
        pushdown(u);
        update(u << 1, l, r, color);
        update(u << 1 | 1, l, r, color);
        pushup(u);
    }
}

Node query(int u, int l, int r)
{
    if(tr[u].l >= l && tr[u].r <= r) return tr[u];
    else if(tr[u].l > r || tr[u].r < l) return Node{};
    else
    {
        pushdown(u);
        Node res = {};
        Node left = query(u << 1, l, r);
        Node right = query(u << 1 | 1, l, r);
        pushup(res, left, right);
        return res;
    }
}

int main()
{
    cin >> n >> t >> m;
    build(1, 1, n);
    char op;
    int a, b, c;
    while(m--)
    {
        cin >> op >> a >> b;
        if(a > b) swap(a, b);
        if(op == 'C')
        {
            cin >> c;
            update(1, a, b, c);
        }
        else
        {
            int allcolor = query(1, a, b).all;
            int cnt = 0;
            for(int i = 1; i <= t; i++)
            {
                if(allcolor >> i & 1) cnt++;
            }
            cout << cnt << endl;
        }
    }
}

 

posted @ 2024-12-09 10:51  五月江城  阅读(13)  评论(0编辑  收藏  举报