题目链接
离线所有的操作,依次加边,并查集维护连通性,链表维护每个联通块的节点,每次合并时将两个链表首位相接,以此保证任何一个曾经存在过的连通块都是链表上连续的一段,这样我们就可以用线段树来维护连通块的修改和查询操作了。
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 300030, inf = 0x3f3f3f3f;
char buf;
inline int read() {
int f = 1, rst = 0;
do buf = getchar(); while (! isdigit(buf) and buf != '-');
if (buf == '-') f = -1, buf = getchar();
while (isdigit(buf)) rst = rst*10 + buf - '0', buf = getchar();
return rst*f;
}
struct query {
int kd, x, v;
query() {}
query(int __kd, int __x, int __v): kd(__kd), x(__x), v(__v) {
// printf("%d %d %d\n", kd, x, v);
}
}lib[N];
int n, q, a[N], fa[N], nxt[N], ed[N], tot, id[N], val[N];
char str[10];
int maxv[N<<1], gl, gr, gx, mark[N<<1];
#define g(l, r) (l + r | l != r)
#define o g(l, r)
#define ls g(l, mid)
#define rs g(mid + 1, r)
#define set(l, r, x) do {gl = l, gr = r, gx = x;} while(0)
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
inline void update(int l, int r) {
if (l == r) return;
int mid = l + r >> 1;
maxv[o] = max(maxv[ls], maxv[rs]);
}
void build(int l, int r) {
if (l == r) {
maxv[o] = val[l]; return;
} int mid = l + r >> 1;
build(l, mid); build(mid + 1, r);
update(l, r);
}
inline void init() {
for (int i = 1; i <= n; i++) if (find(i) == i)
for (int j = i; j; j = nxt[j]) id[j] = ++tot, val[tot] = a[j];
for (int i = 1; i <= n; i++) fa[i] = ed[i] = i;
build(1, n);
}
inline void push(int l, int r) {
if (! mark[o] or l == r) return;
int mid = l + r >> 1;
mark[ls] += mark[o]; maxv[ls] += mark[o];
mark[rs] += mark[o]; maxv[rs] += mark[o];
mark[o] = 0;
}
inline void Change(int l, int r) {
push(l, r);
if (gl <= l and r <= gr) {
mark[o] += gx; maxv[o] += gx; push(l, r); return;
} int mid = l + r >> 1;
if (gl <= mid) Change(l, mid);
if (gr >= mid + 1) Change(mid + 1, r);
update(l, r);
}
inline void change(int l, int r, int x) {
set(l, r, x); Change(1, n);
}
inline void GetMax(int l, int r) {
push(l, r);
if (gl <= l and r <= gr) {
gx = max(gx, maxv[o]); return;
} int mid = l + r >> 1;
if (gl <= mid) GetMax(l, mid);
if (gr >= mid + 1) GetMax(mid + 1, r);
// update(l, r);
}
inline int getMax(int l, int r) {
set(l, r, -inf); GetMax(1, n); return gx;
}
int main() {
n = read(); memset(maxv, 0xd0, sizeof(maxv));
for (int i = 1; i <= n; i++) a[i] = read(), ed[i] = fa[i] = i;
q = read();
for (int i = 1; i <= q; i++) {
scanf("%s", str);
if (*str == 'U') {
int x = read(), y = read();
lib[i] = query(0, x, y);
int r1 = find(x), r2 = find(y);
if (r1 == r2) continue;
fa[r2] = r1; nxt[ed[r1]] = r2; ed[r1] = ed[r2];
} else if (*str == 'A') {
if (str[1] == '1') {
int x = read(), v = read();
lib[i] = query(1, x, v);
} else if (str[1] == '2') {
int x = read(), v = read();
lib[i] = query(2, x, v);
} else lib[i] = query(3, 0, read());
} else {
if (str[1] == '1') lib[i] = query(4, read(), 0);
else if (str[1] == '2') lib[i] = query(5, read(), 0);
else lib[i] = query(6, 0, 0);
}
} init();
for (int i = 1; i <= q; i++) {
int kd = lib[i].kd, x = lib[i].x, v = lib[i].v;
if (! kd) {
int r1 = find(x), r2 = find(v);
if (r1 == r2) continue;
fa[r2] = r1; ed[r1] = ed[r2];
} else if (kd == 1) change(id[x], id[x], v);
else if (kd == 2) change(id[find(x)], id[ed[find(x)]], v);
else if (kd == 3) change(1, n, v);
else if (kd == 4) printf("%d\n", getMax(id[x], id[x]));
else if (kd == 5) printf("%d\n", getMax(id[find(x)], id[ed[find(x)]]));
else printf("%d\n", getMax(1, n));
}
return 0;
}