[BZOJ3091]城市旅行

城市旅行

Description
這裏寫圖片描述
Input
這裏寫圖片描述
Output
這裏寫圖片描述
Sample Input
4 5
1 3 2 5
1 2
1 3
2 4
4 2 4
1 2 4
2 3 4
3 1 4 1
4 1 4
Sample Output
16/3
6/1
HINT
對於所有數據滿足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N

Solution
以後打tag都打即時tag
注意push_down的時候不要對null作修改
建LCT的時候按輸入一個一個link會T,random_shuffle一下可以有效加快速度,直接dfs更快

Code

#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
typedef long long ll;
template<typename T> inline void read(T &x){
    x = 0; T f = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
    while (isdigit(ch))  { x = x * 10 + ch - '0'; ch = getchar(); }
    x *= f;
}

const int N = 51000;
struct Node{
    Node *c[2], *fa;
    ll val, sz, sum[3], exp;   
    bool rev_mark; ll add_mark;
    inline int d(){
        if (fa->c[0] != this && fa->c[1] != this) return -1;
        return fa->c[1] == this;
    }
    inline void sc(Node *p, int d) { c[d] = p; p->fa = this; }
    inline void push_up(){
        sz = c[0]->sz + c[1]->sz + 1;
        sum[0] = c[0]->sum[0]+c[1]->sum[0]+val;
        sum[1] = c[0]->sum[1]+c[1]->sum[1]+(c[0]->sz+1)*(val+c[1]->sum[0]);
        sum[2] = c[0]->sum[2]+c[1]->sum[2]+(c[1]->sz+1)*(val+c[0]->sum[0]);
        exp = c[0]->exp+c[1]->exp+(c[0]->sz+1)*(c[1]->sz+1)*val+(c[1]->sz+1)*c[0]->sum[1]+(c[0]->sz+1)*c[1]->sum[2];
    }
    inline void add(ll dt){
        val += dt;
        sum[0] += sz*dt;
        sum[1] += dt*sz*(sz+1)/2; sum[2] += dt*sz*(sz+1)/2;
        exp += dt*sz*(sz+1)*(sz+2)/6;
        add_mark += dt;
    }
    inline void reverse(){ swap(sum[1], sum[2]); swap(c[0], c[1]), rev_mark ^= 1; }
    void push_down();
}pool[N<<1], *null=pool, *tail=pool+1, *loc[N];
void Node :: push_down(){
    if (fa->c[0] == this || fa->c[1] == this) fa->push_down();
    if (rev_mark){ 
        c[0]->reverse(); 
        c[1]->reverse(); 
        rev_mark = 0;
    }
    if (add_mark){ 
        if (c[0] != null) c[0]->add(add_mark);
        if (c[1] != null) c[1]->add(add_mark); 
        add_mark = 0;
    }
}
int n, q;
struct Edge{ int v; Edge *nxt; }POOL[N<<1], *TAIL=POOL, *g[N];

inline void setnull(){
    null->c[0] = null->c[1] = null->fa = null;
    null->sz = null->sum[0] = null->sum[1] = null->sum[2] = null->val = null->exp = 0;
    null->add_mark = null->rev_mark = 0;
}
inline Node *newNode(ll dt){
    tail->c[0] = tail->c[1] = tail->fa = null; tail->sz = 1;
    tail->sum[0] = tail->sum[1] = tail->sum[2] = tail->val = tail->exp = dt;
    tail->add_mark = tail->rev_mark = 0;
    return tail++;
}
void rot(Node *x){
    Node *y = x->fa; int d = x->d();
    if (y->d() == -1) x->fa = y->fa; else y->fa->sc(x, y->d());
    y->sc(x->c[!d], d); y->push_up();
    x->sc(y, !d);
}
void splay(Node *x){
    for (x->push_down(); x->d() != -1; ){
        if (x->fa->d() == -1) rot(x);
        else x->d() == x->fa->d() ?
             (rot(x->fa), rot(x)) : (rot(x), rot(x));
    }
    x->push_up();
}
void access(Node *x){
    for (Node *t = null; x != null; t = x, x = x->fa)
        splay(x), x->c[1]=t, x->push_up();    
}
Node *find_root(Node *x){
    access(x); splay(x);
    while (x->c[0] != null) x = x->c[0];
    return x;
}
void make_root(Node *x){ access(x); splay(x); x->reverse(); }
void link(Node *x, Node *y){
    if (find_root(x) == find_root(y)) return;
    make_root(x); x->fa = y;
}
void cut(Node *x, Node *y){
    if (x == y || find_root(x) != find_root(y)) return;
    make_root(x); access(y); splay(y);
    if (y->c[0] == x && x->c[1] == null){
        y->c[0] = x->fa = null;
        y->push_up();
    }
}
void solve(Node *x, Node *y){
    if (find_root(x) != find_root(y)) { puts("-1"); return; }
    make_root(x); access(y); splay(y);
    ll up = y->exp, down = y->sz*(y->sz+1)/2, d = __gcd(up, down);
    printf("%lld/%lld\n", up/d, down/d); 
}
void modify(Node *x, Node *y, ll dt){ 
    if (find_root(x) != find_root(y)) return;
    make_root(x); access(y); splay(y); y->add(dt);
}
void build(int x, int last){
    if (last) loc[x]->fa = loc[last];
    for (Edge *p = g[x]; p; p=p->nxt) if (p->v != last) build(p->v, x);
}
inline void addedge(int u, int v){
    TAIL->v = v; TAIL->nxt = g[u]; g[u] = TAIL++;
    TAIL->v = u; TAIL->nxt = g[v]; g[v] = TAIL++;
}
int main(){
    setnull();
    read(n); read(q);
    rep(i, 1, n){ ll w; read(w); loc[i] = newNode(w); }
    rep(i, 1, n-1){ 
        int u, v; read(u); read(v);
        addedge(u, v);
    }
    build(1, 0);
    for (; q; q--){ int opt, u, v; ll d;
        read(opt); read(u); read(v);
        if (opt == 1) cut(loc[u], loc[v]);
        else if (opt == 2) link(loc[u], loc[v]);
        else if (opt == 4){ solve(loc[u], loc[v]); }
        else { read(d); modify(loc[u], loc[v], d); }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章