首先是看了一下官方题解:https://codeforces.com/blog/entry/99942
了解了一下可以对颜色 c 开一个延迟标记 lazy[c](我代码实现的时候是用 tag[c] 表示的,是一个意思)。
然后看了一下一位大佬的代码,有了一些启发。大佬的代码链接:https://codeforces.com/contest/1638/submission/146402136
主要这位大佬写的线段树的风格和我写的比较像,比较能接受一点。同时这位大佬的代码中关于的 add 值的处理也对我有很大的启发。启发在于:之前我 pushdown 的时候,不光是颜色传递下去,值也传递下去了,但是其实值可以保留在当前这个线段上,在查询的时候直接加上去就好了。
然后就是我 最困惑的地方:关于颜色的信息,正确的写法好像都是开了2个信息维护,但是我就只开了一个信息维护,不太清楚为什么。
比如上面大佬提交的代码,是开了两个数组维护颜色信息(col 和 cov),但是我是只开了一个数组(我代码中的 color 数组)。
所以我不知道我是哪里写错了。或者那个地方没有想明白。想请各位大佬帮我看一下我的代码,我将从所有解答中选出最好的代码并以 5 块钱作为酬谢。
下面是我的代码(也可点击 https://codeforces.com/contest/1638/submission/146582163 直接查看)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int n, q, color[maxn<<2];
long long add[maxn<<2], tag[maxn];
char op[11];
void push_up(int rt) {
color[rt] = (color[rt<<1] == color[rt<<1|1]) ? color[rt<<1] : 0;
}
void push_down(int l, int r, int rt) {
assert(l < r);
if (color[rt]) {
color[rt<<1] = color[rt<<1|1] = color[rt];
color[rt] = 0;
}
}
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
void build(int l, int r, int rt) {
if (l == r) {
color[rt] = 1;
return;
}
int mid = (l + r) / 2;
build(lson);
build(rson);
push_up(rt);
}
// 将 [L,R] 颜色变为 c
void update(int L, int R, int c, int l, int r, int rt) {
if (L <= l && r <= R && color[rt]) {
add[rt] += tag[color[rt]] - tag[c];
color[rt] = c;
return;
}
int mid = (l + r) / 2;
push_down(l, r, rt);
if (L <= mid) update(L, R, c, lson);
if (R > mid) update(L, R, c, rson);
push_up(rt);
}
// 将所有颜色为c的节点加上x
void addcolor(int c, int x) {
tag[c] += x;
}
// 查询节点p的权值
long long query(int p, int l, int r, int rt) {
if (l == r) {
return add[rt] + tag[color[rt]];
}
push_down(l, r, rt);
int mid = (l + r) / 2;
return add[rt] + (p <= mid) ? query(p, lson) : query(p, rson);
}
int main() {
scanf("%d%d", &n, &q);
build(1, n, 1);
while (q --) {
scanf("%s", op);
if (op[0] == 'C') {
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
update(l, r, c, 1, n, 1);
}
else if (op[0] == 'A') {
int c, x;
scanf("%d%d", &c, &x);
addcolor(c, x);
}
else {
int i;
scanf("%d", &i);
printf("%lld\n", query(i, 1, n, 1));
}
}
return 0;
}
其中我用 color[rt] 表示 rt 节点对应的颜色信息,若 rt 维护的区间中所有节点颜色都是相同的一种颜色 c,则 color[rt] = c;否则(不是所有颜色都相同),则 color[rt] = 0。
add[rt] 表示 rt 对应的区间累积加上的值。
我在 push_up 和 push_down 的时候更新的只有 color 的信息。