[BZOJ1036][ZJOI2008]树的统计Count

来源:互联网 发布:水电算量软件 编辑:程序博客网 时间:2024/05/21 18:32

[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;}
0 0
原创粉丝点击