传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3083

这道题最重要的一点,树链剖分也是一种dfs序,于是我们记录时间戳,就既可以维护路径上的信息,也可以维护子树上的信息。

bzoj上倒数第三,-_-|||,然后看了身下的WJMZBMR,吓傻了。。。。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <list>
#include <stack>
#include <cmath>
using namespace std;
typedef long long LL;
#define INF 1000000000000LL
#define idx(l, r) ((l + r) | (l != r))
#define mid ((l + r) >> 1)
const int maxn = 100010;
struct node {
    int x, f;
    bool vis;
    node() {}
    node(int a, int b, bool c) {
        x = a; f = b; vis = c;
    }
};
stack <node> q;
list <int> edge[maxn];
int num[maxn], top[maxn], to[maxn], sz[maxn], dep[maxn], fa[maxn], rs[maxn];
int f[maxn][20];
LL a[maxn], mi[maxn * 2], lazy[maxn * 2];
int n, cnt, rt, tot, m;
void get(int &tmp) {
    tmp = 0;
    char ch = getchar();
    for(; ch < '0' || ch > '9'; ch = getchar());
    for(; ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
    return;
}
void dfs() {
    q.push(node(rt, 0, false));
    while(!q.empty()) {
        node t = q.top();
        if(!t.vis) {
            q.top().vis = true;
            fa[t.x] = t.f;
            for(list <int> :: iterator p = edge[t.x].begin(); p != edge[t.x].end(); p ++) {
                if(*p == t.f) continue;
                dep[*p] = dep[t.x] + 1;
                q.push(node(*p, t.x, false));
            }
        } else {
            for(list <int> :: iterator p = edge[t.x].begin(); p != edge[t.x].end(); p ++) {
                if(*p == t.f) continue;
                sz[t.x] += sz[*p];
                if(!to[t.x] || sz[*p] > sz[to[t.x]]) to[t.x] = *p;
            }
            sz[t.x] ++;
            q.pop();
        }
    }
    return;
}
void split() {
    q.push(node(rt, 0, false));
    while(!q.empty()) {
        node t = q.top();
        if(!t.vis) {
            q.top().vis = true;
            num[t.x] = ++tot;
            for(list <int> :: iterator p = edge[t.x].begin(); p != edge[t.x].end(); p ++) {
                if(*p == t.f || *p == to[t.x]) continue;
                top[*p] = *p;
                q.push(node(*p, t.x, false));
            }
            if(to[t.x]) {
                top[to[t.x]] = top[t.x];
                q.push(node(to[t.x], t.x, false));
            }
        } else {
            rs[t.x] = tot;
            q.pop();
        }
    }
    return;
}
void dfs2() {
    q.push(node(rt, 0, false));
    while(!q.empty()) {
        node t = q.top();
        if(!t.vis) {
            q.top().vis = true;
            if(!t.f) {
                for(int i = 0; i <= cnt; i ++) f[t.x][i] = t.x;
            } else {
                f[t.x][0] = t.f;
                for(int i = 1; i <= cnt; i ++) f[t.x][i] = f[f[t.x][i - 1]][i - 1];
            }
            for(list <int> :: iterator p = edge[t.x].begin(); p != edge[t.x].end(); p ++) {
                if(*p == t.f) continue;
                q.push(node(*p, t.x, false));
            }
        } else q.pop();
    }
    return;
}
void go(int &x, int dd) {
    for(int i = 0; i <= cnt; i ++) {
        if((dd >> i) & 1) {
            x = f[x][i];
        }
    }
    return;
}
int lca(int u, int v) {
    if(dep[u] < dep[v]) swap(u, v);
    go(u, dep[u] - dep[v]);
    for(int i = cnt; i >= 0; i --) {
        if(f[u][i] != f[v][i]) {
            u = f[u][i]; v = f[v][i];
        }
    }
    if(u != v) {
        u = f[u][0]; v = f[v][0];
    }
    return u;
}
void push_down(int l, int r) {
    if(!lazy[idx(l, r)]) return;
    mi[idx(l, r)] = lazy[idx(l, r)];
    if(l < r) {
        lazy[idx(l, mid)] = lazy[idx(mid + 1, r)] = lazy[idx(l, r)];
    }
    lazy[idx(l, r)] = 0;
    return;
}
void push_up(int l, int r) {
    push_down(l, mid); push_down(mid + 1, r);
    mi[idx(l, r)] = min(mi[idx(l, mid)], mi[idx(mid + 1, r)]);
    return;
}
void insert(int l, int r, int a, int b, LL d) {
    if(l > b || r < a) return;
    if(a <= l && r <= b) {
        mi[idx(l, r)] = d;
        lazy[idx(l, r)] = d;
        return;
    }
    push_down(l, r);
    insert(l, mid, a, b, d);
    insert(mid + 1, r, a, b, d);
    push_up(l, r);
    return;
}
LL ask(int l, int r, int a, int b) {
    if(a > b) return INF;
    if(l > b || r < a) return INF;
    push_down(l, r);
    if(a <= l && r <= b) return mi[idx(l, r)];
    LL p = min(ask(l, mid, a, b), ask(mid + 1, r, a, b));
    push_up(l, r);
    return p;
}
void update(int u, int v, LL d) {
    while(top[u] != top[v]) {
        if(dep[top[u]] < dep[top[v]]) swap(u, v);
        insert(1, n, num[top[u]], num[u], d);
        u = fa[top[u]];
    }
    if(dep[u] > dep[v]) swap(u, v);
    insert(1, n, num[u], num[v], d);
    return;
}
int main() {
    scanf("%d%d", &n, &m);
    int u, v;
    for(int i = 1; i < n; i ++) {
        scanf("%d%d", &u, &v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    for(int i = 1; i <= n; i ++) {
        scanf("%lld", &a[i]);
    }
    scanf("%d", &rt);
    top[rt] = rt;
    dep[rt] = 1;
    dfs();
    split();
    cnt = (int)ceil(log2(n));
    dfs2();
    for(int i = 0; i < maxn * 2; i ++) mi[i] = INF;
    for(int i = 1; i <= n; i ++) {
        insert(1, n, num[i], num[i], a[i]);
    }
    int opt, id = rt;
    LL w;
    for(int i = 1; i <= m; i ++) {
        scanf("%d", &opt);
        if(opt == 1) {
            scanf("%d", &u);
            id = u;
        } else if(opt == 2) {
            scanf("%d%d%lld", &u, &v, &w);
            update(u, v, w);
        } else {
            scanf("%d", &u);
            int t = lca(u, id);
            if(u == id) {
                printf("%lld\n", ask(1, n, 1, n));
            } else if(t == id) {
                printf("%lld\n", ask(1, n, num[u], rs[u]));
            } else if(t == u) {
                int p = id;
                go(p, dep[id] - dep[u] - 1);
                printf("%lld\n", min(ask(1, n, 1, num[p] - 1), ask(1, n, rs[p] + 1, n)));
            } else {
                printf("%lld\n", ask(1, n, num[u], rs[u]));
            }
        }
    }
    return 0;
}