[bzoj3786]星系探索【欧拉序】【splay】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=3786
【题解】
  用splay维护欧拉序,修改相当于将一段区间移到另一个位置。子树加就是区间加,查询链的答案相当于一段前缀和,都是splay基本操作。
  时间复杂度 O ( M l o g N )
【代码】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [bzoj3786]
    Points :    splay
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       200005
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Edge{
    int data, next;
}e[N * 2];
struct Tree{
    ll sum, num1, num0, tag, now;
    int pl, pr, fa, f;
}T[N];
int id[N], num, place, h[N], head[N], in[N], out[N], rt, st[N], top, n, m;
void build(int u, int v){
    e[++place].data = v; e[place].next = head[u]; head[u] = place;
}
void dfs(int x, int fa){
    id[++num] = x; in[x] = num; 
    for (int ed = head[x]; ed != 0; ed = e[ed].next)
        if (e[ed].data != fa)
            dfs(e[ed].data, x);
    id[++num] = -x; out[x] = num;
}
void pushtag(int p){
    if (p == 0 || T[p].tag == 0) return;
    if (T[p].pl != 0){
        int tmp = T[p].pl;
        T[tmp].sum = T[tmp].sum + (T[tmp].num1 - T[tmp].num0) * T[p].tag;
        T[tmp].now += T[p].tag * T[tmp].f;
        T[tmp].tag += T[p].tag;
    }
    if (T[p].pr != 0){
        int tmp = T[p].pr;
        T[tmp].sum = T[tmp].sum + (T[tmp].num1 - T[tmp].num0) * T[p].tag;
        T[tmp].now += T[p].tag * T[tmp].f;
        T[tmp].tag += T[p].tag;
    }
    T[p].tag = 0;
}
void reget(int p){
    if (p == 0) return;
    T[p].num0 = T[T[p].pl].num0 + T[T[p].pr].num0 + (id[p] < 0);
    T[p].num1 = T[T[p].pl].num1 + T[T[p].pr].num1 + (id[p] > 0);
    T[p].sum = T[T[p].pl].sum + T[T[p].pr].sum + T[p].now;
}
void build(int &p, int l, int r, int fa){
    int mid = (l + r) / 2;
    p = mid; T[p].fa = fa;
    if (id[mid] > 0) T[p].f = 1; if (id[mid] < 0) T[p].f = -1;
    if (T[p].f > 0) T[p].num1++; if (T[p].f < 0) T[p].num0++;
    T[p].now = T[p].f * h[abs(id[mid])];
    if (l < mid) build(T[p].pl, l, mid - 1, p);
    if (mid < r) build(T[p].pr, mid + 1, r, p);
    reget(p);
}
void zig(int x){
    int y = T[x].fa;
    if (T[T[y].fa].pl == y)
        T[T[y].fa].pl = x;
        else T[T[y].fa].pr = x;
    T[x].fa = T[y].fa;
    T[T[x].pr].fa = y, T[y].pl = T[x].pr;
    T[y].fa = x; T[x].pr = y; 
    reget(y); reget(x);
}
void zag(int x){
    int y = T[x].fa;
    if (T[T[y].fa].pl == y)
        T[T[y].fa].pl = x;
        else T[T[y].fa].pr = x;
    T[x].fa = T[y].fa;
    T[T[x].pl].fa = y, T[y].pr = T[x].pl;
    T[y].fa = x; T[x].pl = y; 
    reget(y); reget(x);
}
void solve(int x, int w){
    if (x == 0) return;
    pushtag(x);
    solve(T[x].pl, w); 
    solve(T[x].pr, w);
}
void splay(int x){
    pushtag(x);
    if (rt == x) return;
    int tmp = x;
    st[top = 1] = tmp;
    while (T[tmp].fa != 0) st[++top] = tmp = T[tmp].fa;
    for (int i = top; i >= 1; i--) pushtag(st[i]);
    pushtag(T[x].pl), pushtag(T[x].pr);
    while (T[x].fa != rt){
        int y = T[x].fa;
        if (T[y].fa == rt){
            if (T[y].pl == x)
                zig(x); else zag(x);
            continue;
        }
        if (T[T[y].fa].pl == y){
            if (T[y].pl == x) zig(y), zig(x);
                else zag(x), zig(x);
        }
        else if (T[y].pl == x) zig(x), zag(x);
            else zag(y), zag(x);
    }
    if (T[rt].pl == x)
        zig(x); else zag(x);
    rt = x;
}
int findnex(int x){
    splay(x);
    x = T[x].pr;
    while (T[x].pl != 0) x = T[x].pl;
    return x;
}
int findpre(int x){
    splay(x);
    x = T[x].pl;
    while (T[x].pr != 0) x = T[x].pr;
    return x;
}
int main(){
    freopen("bzoj3786.in", "r", stdin);
    freopen("bzoj3786.out", "w", stdout);
    n = read(); num = 1;
    for (int i = 2; i <= n; i++){
        int u = read();
        build(i, u); build(u, i);
    }
    for (int i = 1; i <= n; i++) h[i] = read();
    dfs(1, 0);
    build(rt, 1, num + 1, 0); 
    m = read();
    char opt;
    for (int i = 1; i <= m; i++){
        scanf("\n%c", &opt);
        if (opt == 'Q'){
            int x = read();
            splay(findnex(in[x]));
            pushtag(T[rt].pl);
            printf("%lld\n", T[T[rt].pl].sum);
        }
        if (opt == 'F'){
            int x = read(), w = read();
            int r = findnex(out[x]), l = findpre(in[x]);
            splay(r), splay(l);
            int tmp = T[T[rt].pr].pl;
            T[tmp].sum = T[tmp].sum + (T[tmp].num1 - T[tmp].num0) * w;
            T[tmp].now += w * T[tmp].f;
            T[tmp].tag += w;
        }
        if (opt == 'C'){
            int x = read(), v = read();
            int r = findnex(out[x]), l = findpre(in[x]);
            splay(r), splay(l);
            int tmp = T[T[rt].pr].pl;
            T[tmp].fa = 0; T[T[rt].pr].pl = 0;
            pushtag(tmp); 
            reget(T[rt].pr); reget(rt);
            r = findnex(in[v]), l = in[v];
            splay(r); splay(l);
            T[tmp].fa = T[rt].pr;
            T[T[rt].pr].pl = tmp;
            reget(T[rt].pr); reget(rt);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/d_vanisher/article/details/80529118