bzoj2333 [SCOI2011]棘手的操作

题目

bzoj2333

题解

联通块合后并不需要再拆开,可以考虑离线做法

想办法将各个点按联通块有序排列,接下来就直接用线段树区间维护即可

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;
}
posted @ 2018-04-24 15:21  XYZinc  阅读(200)  评论(0编辑  收藏  举报