由于此题是某校 Online Judge 里面的题目,所以只给出题意。
题意
现在有一个长度为 n n n 的序列,一开始都为 0 0 0。有 m m m 次操作,每一次操作有三个参数 l l l, r r r 和 x x x,保证 l ≤ x ≤ r l\le x \le r l≤x≤r。对于所有满足 l ≤ i ≤ r l\le i\le r l≤i≤r 的 i i i,且 i ≠ x i \not =x i=x,如果 a i a_i ai 不为 0 0 0,则将 a i a_i ai 替换成 x x x。
做法
我们可以用线段树解决这个区间问题,对于每一个线段树节点,如果这个节点所覆盖的一个区间全部是同一个数,用一个 tag
变量存储这个数字,如果这个节点所覆盖的区间全部是非零数,就用一个 vis
变量存储,有零就将 vis
设为
0
0
0,否则为
1
1
1。我们用一个 same
变量存储这个节点的左儿子所覆盖的区间的数是否等于右儿子所覆盖的区间。如果这个区间的数不一样, same
就是
0
0
0。一开始这三个变量的初值分别为
0
0
0,
0
0
0,
1
1
1。
节点维护值
让我们思考一下这三个变量怎么维护:我们有一个节点 p
,然后我们要维护 p
的这三个变量。
如果 p
的左儿子的 vis
和 p
的右儿子的 vis
都是
1
1
1,说明左边的区间和右边的区间都没有
0
0
0,p
的 vis
自然应该设为
1
1
1,否则,就是
0
0
0。如果 p
的左儿子的 tag
不等于 p
右儿子的 tag
,说明左儿子覆盖的区间和右儿子覆盖的区间数不一样,p
的 same
就是
0
0
0,否则,不一定是
1
1
1。因为如果这个区间的数不一样,我们的 tag
就是 0
。如果左儿子的区间和右儿子的区间都是乱的,而它们的 tag
都是
0
0
0。否则,p
的 tag
就应该更新为儿子的 tag
。
操作
然后我们思考如何写修改和查询操作,这个题中,我们只用考虑单点的查询。
修改操作
首先,如果这个节点有 tag
,那么传递 tag
给子节点,再更新自己的值。如果这个区间被修改区间包含而且这个区间没被修改过(tag
为
0
0
0),而且这个区间值都是
0
0
0(vis
为
0
0
0),就直接将这个区间的 tag
设为我们要修改的东西。传递 tag
,然后更新这个区间的值,就可以返回了。否则,如果这个区间全是
1
1
1(vis
为
1
1
1),就不用改了,直接返回。然后修改儿子,更新数据。
查询操作
如果这个节点有 tag
,就传掉,不要影响其他节点。如果已经递归到最底层的节点了,就返回这个节点的 tag
。如果这个区间不包含答案所在位置,直接返回无穷大,然后再子区间的询问中取最小值就行了。
AC Code:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
int n, m;
struct node{
int l, r, vis, tag, same;
};
node t[2400100];
void update(int p) {
if (t[p].l == t[p].r && t[p].tag) {
t[p].vis = 1; return;
}
else t[p].vis = t[p * 2].vis && t[p * 2 + 1].vis;
if (t[p * 2].tag != t[p * 2 + 1].tag) t[p].same = 0;
else t[p].tag = t[p * 2].tag;
}
void pushtag(int p) {
if (!t[p * 2].tag) t[p * 2].tag = t[p].tag, t[p * 2].vis = 1;
if (!t[p * 2 + 1].tag) t[p * 2 + 1].tag = t[p].tag, t[p * 2 + 1].vis = 1;
}
void maketree(int l, int r, int p) {
t[p].l = l;
t[p].r = r;
if (l < r) {
maketree(l, (l + r) / 2, p * 2);
maketree((l + r) / 2 + 1, r, p * 2 + 1);
}
t[p].same = 1;
update(p);
}
void change(int l, int r, int p, int x) {
if (t[p].tag) {
pushtag(p);
update(p);
}
if (l <= t[p].l && t[p].r <= r && !t[p].tag && !t[p].vis) {
t[p].tag = x;
t[p].vis = 1;
pushtag(p);
update(p);
return;
}
if (t[p].vis) return;
if (l > t[p].r || r < t[p].l) {
return;
}
change(l, r, p * 2, x);
change(l, r, p * 2 + 1, x);
update(p);
}
int get(int i, int p) {
if (t[p].tag) {
pushtag(p);
update(p);
}
if (t[p].l == i && t[p].r == i) return t[p].tag;
if (t[p].l > i || t[p].r < i) return 0x3f3f3f3f;
return min(get(i, p * 2), get(i, p * 2 + 1));
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
maketree(1, n, 1);
while (m--) {
int l, r, x;
cin >> l >> r >> x;
if (x > l) change(l, x - 1, 1, x);
if (x < r) change(x + 1, r, 1, x);
}
for (int i = 1; i <= n; i++) cout << get(i, 1) << ' ';
return 0;
}