[BZOJ1036][ZJOI2008]樹的統計Count

[ZJOI2008]樹的統計Count

Description
一棵樹上有n個節點,編號分別爲1到n,每個節點都有一個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作: I. CHANGE u t : 把結點u的權值改爲t II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值 III. QSUM u v: 詢問從點u到點v的路徑上的節點的權值和 注意:從點u到點v的路徑上的節點包括u和v本身
Input
輸入的第一行爲一個整數n,表示節點的個數。接下來n – 1行,每行2個整數a和b,表示節點a和節點b之間有一條邊相連。接下來n行,每行一個整數,第i行的整數wi表示節點i的權值。接下來1行,爲一個整數q,表示操作的總數。接下來q行,每行一個操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式給出。 對於100%的數據,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。
Output
對於每個“QMAX”或者“QSUM”的操作,每行輸出一個整數表示要求輸出的結果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16

Solution
LCT模板題。
一些經驗談:
1.splay前把rev標記都傳一遍才行,要不然rot的時候各種重新連邊會歪掉,原因暫時我還不明白。
2.LCT的access操作取出的是x到樹根的鏈,要想提取x到y的鏈,讓x成爲根(access之後全部反向),再access y即可
3.手動設置null結點可以有效防止訪問空指針,注意合理設置null結點的參數消除它對其它點的影響即可

Code

#include <bits/stdc++.h>
using namespace std;

#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long ll;
typedef pair<int, int> PII;
typedef vector<int> VI;
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 INF = ~0U>>2;
const int N = 30100;
struct Node{
    int sum, mx, val; bool rev; 
    Node *c[2], *fa;
    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_down(){
        if (rev){
            c[0]->rev ^= 1; c[1]->rev ^= 1; rev ^= 1;
            swap(c[0], c[1]);
        }
    }
    inline void push_up(){
        sum = c[0]->sum + c[1]->sum + val;
        mx = max(val, max(c[0]->mx, c[1]->mx));
    }
}pool[N], *null=pool, *tail=pool+1, *LCT[N], *q[N];
int n, m, u[N], v[N], qn;
void setnull(){
    null->fa = null->c[0] = null->c[1] = null;
    null->sum = 0; null->mx = -INF;
}
Node *newNode(int w){
    tail->c[0] = tail->c[1] = tail->fa = null; 
    tail->sum = tail->mx = tail->val = w; tail->rev = 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 (Node *p = q[qn = 1] = x; p->d()!=-1; q[++qn] = p = p->fa);
    while (qn) q[qn--]->push_down();    
    for (; 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();
    }
}
void makeroot(Node *x){ access(x); splay(x); x->rev ^= 1;}
void link(Node *x, Node *y){ makeroot(x); x->fa = y; }
void split(Node *x, Node *y){ makeroot(x); access(y); splay(y); }
int main(){
    setnull(); 
    read(n);
    rep(i, 1, n-1) read(u[i]), read(v[i]);
    rep(i, 1, n){ int w; read(w); LCT[i] = newNode(w); }   
    rep(i, 1, n-1) link(LCT[u[i]], LCT[v[i]]);

    read(m);
    for (; m; m--){ char opt[10]; int u, v;
        scanf("%s", opt); read(u); read(v);    
        if (opt[1] == 'H'){splay(LCT[u]); LCT[u]->val = v; LCT[u]->push_up();}
        else if (opt[1] == 'M'){split(LCT[u], LCT[v]); printf("%d\n", LCT[v]->mx);}
        else {split(LCT[u], LCT[v]); printf("%d\n", LCT[v]->sum);}
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章