bzoj2333 [SCOI2011]棘手的操作
题目
题解
联通块合后并不需要再拆开,可以考虑离线做法
想办法将各个点按联通块有序排列,接下来就直接用线段树区间维护即可
fa[i] 记录 i 所处联通块的起始点
ed[i] 记录 以i为起始点 的联通块的终止点
nt[i] 记录 i 的下一个节点
#include <bits/stdc++.h>
using namespace std;
const int N = 300005;
int n, Q, a[N];
int dfn[N], w[N], t;
int fa[N], nt[N], ed[N];
inline int read()
{
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
struct node
{
int op, x, y;
}q[N];
struct tree
{
int l, r, d, mx;
}T[N << 3];
int findf(int x)
{
if(x == fa[x]) return x;
return fa[x] = findf(fa[x]);
}
void init()
{
n = read();
for(int i = 1; i <= n; i++) a[i] = read(), fa[i] = ed[i] = i;
Q = read();
for(int i = 1; i <= Q; i++)
{
char s[10]; scanf("%s", s);
if(s[0] == 'U')
{
int x = read(), y = read();
q[i].op = 1; q[i].x = x; q[i].y = y;
x = findf(x); y = findf(y);
if(x == y) continue;
fa[y] = x;
nt[ed[x]] = y;
ed[x] = ed[y];
}
else if(s[0] == 'A')
{
if(s[1] == '1') {q[i].op = 2; q[i].x = read(); q[i].y = read();}
else if(s[1] == '2') {q[i].op = 3; q[i].x = read(); q[i].y = read();}
else {q[i].op = 4; q[i].x = read();}
}
else
{
if(s[1] == '1') {q[i].op = 5; q[i].x = read();}
else if(s[1] == '2') {q[i].op = 6; q[i].x = read();}
else q[i].op = 7;
}
}
}
void get_id()
{
for(int i = 1; i <= n; i++)
if(findf(i) == i)
{
for(int j = i; findf(j) == i; j = nt[j])
{dfn[j] = ++t; w[t] = a[j];}
}
}
void pushup(int p) {T[p].mx = max(T[p << 1].mx, T[p << 1 | 1].mx);}
void pushdown(int p)
{
if(!T[p].d) return;
T[p << 1].d += T[p].d; T[p << 1].mx += T[p].d;
T[p << 1 | 1].d += T[p].d; T[p << 1 | 1].mx += T[p].d;
T[p].d = 0;
}
void build(int p, int x, int y)
{
T[p].l = x; T[p].r = y;
if(x == y) {T[p].mx = w[x]; return;}
int mid = (x + y) >> 1;
build(p << 1, x, mid); build(p << 1 | 1, mid + 1, y);
pushup(p);
}
void update(int p, int x, int y, int v)
{
int pl = T[p].l, pr = T[p].r;
if(pl == x && pr == y) {T[p].d += v; T[p].mx += v; return;}
pushdown(p);
int mid = (pl + pr) >> 1;
if(y <= mid) update(p << 1, x, y, v);
else if(x > mid) update(p << 1 | 1, x, y, v);
else {update(p << 1, x, mid, v); update(p << 1 | 1, mid + 1, y, v);}
pushup(p);
}
int query_max(int p, int x, int y)
{
int pl = T[p].l, pr = T[p].r;
if(pl == x && pr == y) return T[p].mx;
pushdown(p);
int mid = (pl + pr) >> 1;
if(y <= mid) return query_max(p << 1, x, y);
else if(x > mid) return query_max(p << 1 | 1, x, y);
else return max(query_max(p << 1, x, mid), query_max(p << 1 | 1, mid + 1, y));
}
void solve()
{
for(int i = 1; i <= n; i++) fa[i] = ed[i] = i;
for(int i = 1; i <= Q; i++)
{
int x = q[i].x, y = q[i].y;
if(q[i].op == 1)
{
x = findf(x); y = findf(y);
if(x == y) continue;
fa[y] = x; ed[x] = ed[y];
}
else if(q[i].op == 2) update(1, dfn[x], dfn[x], y);
else if(q[i].op == 3) update(1, dfn[findf(x)], dfn[ed[findf(x)]], y);
else if(q[i].op == 4) update(1, 1, n, x);
else if(q[i].op == 5) printf("%d\n", query_max(1, dfn[x], dfn[x]));
else if(q[i].op == 6) printf("%d\n", query_max(1, dfn[findf(x)], dfn[ed[findf(x)]]));
else printf("%d\n", query_max(1, 1, n));
}
}
int main()
{
init();
get_id();
build(1, 1, n);
solve();
return 0;
}