洛谷题单指南-线段树-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;
}
}
}