[BZOJ4817][SDOI2017]树点涂色(DFS序+LCA+树剖+LCT)

来源:互联网 发布:淘宝店铺运动服简介 编辑:程序博客网 时间:2024/05/17 02:13

我一眼以为是裸树剖,但是看完问题就知道不是那么容易了。因为只用树剖不能很好地维护操作3的结果。
首先,按照原树,构建出一个全部都是虚边的LCT,并用树剖维护每个点到根节点的路径权值val。可以发现,每个点到根节点的路径权值就是每个点到根节点的路径上实链的个数。
我们发现,操作1实际上就是LCTAccess的操作。在Access的操作中,如果一条实边变成虚边,那么将连接这条边的深度较大的节点的子树里所有点的val1(因为实链数量就等于虚边数量+1),如果一条虚边变成实边,那么将连接这条边的深度较大的节点的子树里所有点的val1
这样,询问2其实就是求val[x]+val[y]val[lca(x,y)]2+1的值,询问3就是求x的子树最大值。在以上,由于同一个子树里的节点DFS序是一段连续的区间,所以对于子树的修改询问,直接提取对应的DFS序区间即可。
代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define p2 p << 1#define p3 p << 1 | 1using namespace std;inline int read() {    int res = 0; bool bo = 0; char c;    while (((c = getchar()) < '0' || c > '9') && c != '-');    if (c == '-') bo = 1; else res = c - 48;    while ((c = getchar()) >= '0' && c <= '9')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}const int N = 1e5 + 5, LogN = 24;int n, m, ecnt, nxt[N << 1], adj[N], go[N << 1], fa_s[N], lc[N], rc[N],QAQ, fa[N][LogN], dep[N], sze[N], son[N], top[N], pos[N], idx[N], T[N << 2],add[N << 2], ml[N];void add_edge(int u, int v) {    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;}int which(int x) {return rc[fa_s[x]] == x;}bool is_root(int x) {    return !fa_s[x] || (lc[fa_s[x]] != x && rc[fa_s[x]] != x);}void upd(int x) {    ml[x] = lc[x] ? ml[lc[x]] : x;}void rotate(int x) {    int y = fa_s[x], z = fa_s[y], b = lc[y] == x ? rc[x] : lc[x];    if (z && !is_root(y)) (lc[z] == y ? lc[z] : rc[z]) = x;    fa_s[x] = z; fa_s[y] = x; if (b) fa_s[b] = y;    if (lc[y] == x) rc[x] = y, lc[y] = b;    else lc[x] = y, rc[y] = b; upd(y); upd(x);}void splay(int x) {    while (!is_root(x)) {        if (!is_root(fa_s[x])) {            if (which(x) == which(fa_s[x])) rotate(fa_s[x]);            else rotate(x);        }        rotate(x);    }    upd(x);}void dfs1(int u, int fu) {    int i; fa[u][0] = fu; dep[u] = dep[fu] + 1; sze[u] = 1;    for (i = 0; i <= 19; i++) fa[u][i + 1] = fa[fa[u][i]][i];    for (int e = adj[u], v; e; e = nxt[e]) {        if ((v = go[e]) == fu) continue;        dfs1(v, u); sze[u] += sze[v];        if (sze[v] > sze[son[u]]) son[u] = v;    }}void dfs2(int u, int fu) {    if (son[u]) {        top[son[u]] = top[u];        idx[pos[son[u]] = ++QAQ] = son[u];        dfs2(son[u], u);    }    for (int e = adj[u], v; e; e = nxt[e]) {        if ((v = go[e]) == fu || v == son[u]) continue;        top[v] = v; idx[pos[v] = ++QAQ] = v; dfs2(v, u);    }}void build(int l, int r, int p) {    if (l == r) return (void) (T[p] = dep[idx[l]]);    int mid = l + r >> 1;    build(l, mid, p2); build(mid + 1, r, p3);    T[p] = max(T[p2], T[p3]);}void down(int p) {    add[p2] += add[p]; add[p3] += add[p]; add[p] = 0;}void upt(int p) {    T[p] = max(T[p2] + add[p2], T[p3] + add[p3]);}void change(int l, int r, int s, int e, int v, int p) {    if (l == s && r == e) return (void) (add[p] += v);    int mid = l + r >> 1; down(p);    if (e <= mid) change(l, mid, s, e, v, p2);    else if (s >= mid + 1) change(mid + 1, r, s, e, v, p3);    else change(l, mid, s, mid, v, p2),        change(mid + 1, r, mid + 1, e, v, p3);    upt(p);}int query(int l, int r, int s, int e, int p) {    if (l == s && r == e) return T[p] + add[p];    int mid = l + r >> 1, res = 0; down(p);    if (e <= mid) res = query(l, mid, s, e, p2);    else if (s >= mid + 1) res = query(mid + 1, r, s, e, p3);    else res = max(query(l, mid, s, mid, p2),        query(mid + 1, r, mid + 1, e, p3));    upt(p); return res;}void init() {    int i; QAQ = top[1] = pos[1] = idx[1] = 1;    dfs1(1, 0); dfs2(1, 0); build(1, n, 1);    for (i = 1; i <= n; i++) fa_s[i] = fa[i][0], ml[i] = i;}void Access(int x) {    int y;    for (y = 0; x; y = x, x = fa_s[x]) {        splay(x);        if (rc[x]) change(1, n, pos[ml[rc[x]]], pos[ml[rc[x]]] +            sze[ml[rc[x]]]- 1, 1, 1);        if (y) change(1, n, pos[ml[y]], pos[ml[y]] + sze[ml[y]] - 1, -1, 1);        rc[x] = y; if (y) fa_s[y] = x;    }}int lca(int u, int v) {    int i; if (dep[u] < dep[v]) swap(u, v);    for (i = 20; i >= 0; i--) {        if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];        if (u == v) return u;    }    for (i = 20; i >= 0; i--) if (fa[u][i] != fa[v][i])        u = fa[u][i], v = fa[v][i];    return fa[u][0];}int path_query(int u, int v) {    int w = lca(u, v), res;    res = query(1, n, pos[u], pos[u], 1) +        query(1, n, pos[v], pos[v], 1);    return res - (query(1, n, pos[w], pos[w], 1) << 1) + 1;}int main() {    int i, op, x, y; n = read(); m = read();    for (i = 1; i < n; i++) {        x = read(); y = read();        add_edge(x, y); add_edge(y, x);    }    init(); while (m--) {        op = read(); x = read();        if (op == 1) Access(x);        else if (op == 2) y = read(), printf("%d\n", path_query(x, y));        else printf("%d\n", query(1, n, pos[x], pos[x] + sze[x] - 1, 1));    }    return 0;}
原创粉丝点击