BZOJ 3083: 遥远的国度

Description

zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。

第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。

第n+1行,有n个整数,代表所有点的初始防御值。

第n+2行一个整数 id,代表初始的首都为id。

第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。

Output

对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

3 7

1 2

1 3

1 2 3

1

3 1

2 1 1 6

3 1

2 2 2 5

3 1

2 3 3 4

3 1

Sample Output

1

2

3

4

Hint

对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

Solution

乍一看貌似是LCT,其实可以用树链剖分的题目。

我们先以任意一个节点比如y为根树链剖分,那么询问操作分三种情况考虑,假设我们询问的点为x,根节点为root:

  1. x==root
  2. x位于root的子树中(根为y)
  3. root位于x的子树中(根为y)

第一种情况答案就是整棵树最小值。

第二种情况答案就是根为y时x子树中最小值。

第三种情况答案就是根为y时整棵树除了root所在的子树的答案。 第三种情况 (注意2^31>MAX_INT,用unsigned)

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const unsigned INF = 2147483648u;
int n, m;
const int maxn = 100005;
int fa[maxn], top[maxn], siz[maxn], dep[maxn], tid[maxn], son[maxn], id[maxn], dfn[maxn], root;
unsigned lazy[maxn * 4], mi[maxn * 4], A[maxn];
int h[maxn], cnte = 1, clock = 0;
struct edge_type {
    int to, next;
} edge[maxn * 2];
void ins(int x, int y) {
    edge[++cnte].to = y;
    edge[cnte].next = h[x];
    h[x] = cnte;
    edge[++cnte].to = x;
    edge[cnte].next = h[y];
    h[y] = cnte;
}
void add(int x, unsigned val) {
    mi[x] = val;
    lazy[x] = val;
}
void pd(int x) {
    if (lazy[x]) {
        add(x << 1, lazy[x]);
        add(x << 1 | 1, lazy[x]);
        lazy[x] = 0;
    }
}
void pu(int x) {
    mi[x] = min(mi[x << 1], mi[x << 1 | 1]);
}
void change(int now, int l, int r, int ll, int rr, unsigned val) {
    if (ll <= l && r <= rr) return add(now, val);
    int mid = (l + r) >> 1;
    pd(now);
    if (ll <= mid) change(now << 1, l, mid, ll, rr, val);
    if (rr > mid) change(now << 1 | 1, mid + 1, r, ll, rr, val);
    pu(now);
}
int dfs1(int now, int father, int deep) {
    fa[now] = father; dep[now] = deep; siz[now] = 1;
    for (int i = h[now]; i; i = edge[i].next) {
        if (edge[i].to == father) continue;
        siz[now] += dfs1(edge[i].to, now, deep + 1);
        if (siz[edge[i].to] > siz[son[now]])
            son[now] = edge[i].to;
    }
    return siz[now];
}
void dfs2(int now, int father, int tp) {
    tid[now] = ++clock; top[now] = tp; id[clock] = now;
    if (son[now]) {
        dfs2(son[now], now, tp);
        for (int i = h[now]; i; i = edge[i].next) {
            if (edge[i].to == father || edge[i].to == son[now]) continue;
            dfs2(edge[i].to, now, edge[i].to);
        }
    }
    dfn[now] = clock;
}
void build(int now, int l, int r) {
    if (l == r) {
        mi[now] = A[id[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(now << 1, l, mid);
    build(now << 1 | 1, mid + 1, r);
    pu(now);
}
int lca(int x, int y) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    if (dep[x] < dep[y]) swap(x, y);
    return y;
}
void CHANGE(int x, int y, unsigned v) {
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]]) swap(x, y);
        change(1, 1, n, tid[top[x]], tid[x], v);
        x = fa[top[x]];
    }
    if (dep[x] < dep[y]) swap(x, y);
    change(1, 1, n, tid[y], tid[x], v);
}
int wson(int x, int y) {
    int lst;
    while (top[x] != top[y]) {
        lst = top[x];
        x = fa[top[x]];
    }
    if (x == y) return lst;
    return son[y];
}
unsigned query(int now, int l, int r, int ll, int rr) {
    if (ll <= l && r <= rr) return mi[now];
    pd(now);
    int mid = (l + r) >> 1;
    unsigned ret = INF;
    if (ll <= mid) ret = min(ret, query(now << 1, l, mid, ll, rr));
    if (rr > mid) ret = min(ret, query(now << 1 | 1, mid + 1, r, ll, rr));
    return ret;
}
unsigned QUERY(int x) {
    if (root == x) return query(1, 1, n, 1, n);
    if (tid[root] < tid[x] || tid[root] > dfn[x])
        return query(1, 1, n, tid[x], dfn[x]);
    int ws = wson(root, x);
    unsigned ret = INF;
    ret = min(ret, query(1, 1, n, 1, tid[ws] - 1));
    ret = min(ret, query(1, 1, n, dfn[ws] + 1, n));
    return ret;
}
int main() {
    int opt, x, y;
    unsigned z;
    scanf("%d%d", &n, &m);
    for (int i = 1; i < n; ++i) {
        scanf("%d%d", &x, &y);
        ins(x, y);
    }
    for (int i = 1; i <= n; ++i) scanf("%u", A + i);
    scanf("%d", &root);
    dfs1(root, 0, 1);
    dfs2(root, 0, root);
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        scanf("%d", &opt);
        if (opt == 1) scanf("%d", &root);
        if (opt == 2) {
            scanf("%d%d%u", &x, &y, &z);
            CHANGE(x, y, z);
        }
        if (opt == 3) {
            scanf("%d", &x);
            printf("%u\n", QUERY(x));
        }
    }
    return 0;
}