• HEOI&TJOI2016 树


    标准意义上第一道非模板树剖题,虽然我并不认为它是树剖

    另:这是一道水题,第二道本省省选题(菜的一批)

    Description

    link

    题意简述:给一棵树,支持两种操作:

    1.对一个节点打标记

    2.求一个节点距离最近的直系祖先(就是根到它链上的那种节点)

    定义:自己也算自己的祖先

    Solution

    [Begin ]

    首先树和序列转化,求一波 (dfn)

    整一棵线段树,维护这个序列

    修改的时候就变成了了区间取 (max),这里不是那种纯 (max)

    如果询问就变成了单点查询

    这里有一个问题:我们在 (push\_down) (或者你叫它 (spread))的时候要取的是 (max),但是我们在 (push\_up) 的时候是维护的子树上面最小的深度编号

    这样有点玄学剪枝的意味,但是正确性可以意会(毕竟是先取 (max) 再取 (min)

    [Q.A.D ]

    (P.S.) 博主知道是(QED)

    (为啥我觉得不是树剖??)

    Code

    
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    namespace yspm {
    inline int read() {
        int res = 0, f = 1;
        char k;
        while (!isdigit(k = getchar()))
            if (k == '-')
                f = -1;
        while (isdigit(k)) res = res * 10 + k - '0', k = getchar();
        return res * f;
    }
    const int N = 1e5 + 10;
    struct node {
        int l, r, maxx, add;
    #define add(p) t[p].add
    #define l(p) t[p].l
    #define r(p) t[p].r
    #define maxx(p) t[p].maxx
    } t[N << 2];
    struct edge {
        int to, nxt;
    } e[N << 1];
    int head[N], cnt, tim, id[N], dep[N], sz[N], son[N], top[N], fa[N], n, T;
    inline void adde(int u, int v) {
        e[++cnt].nxt = head[u];
        e[cnt].to = v;
        return head[u] = cnt, void();
    }
    inline void dfs1(int x, int f) {
        fa[x] = f;
        dep[x] = dep[f] + 1;
        sz[x] = 1;
        for (int i = head[x]; i; i = e[i].nxt) {
            int t = e[i].to;
            if (t == f)
                continue;
            dfs1(t, x);
            sz[x] += sz[t];
            if (sz[t] > sz[son[x]])
                son[x] = t;
        }
        return;
    }
    inline void dfs2(int x, int topf) {
        id[x] = ++tim;
        top[x] = topf;
        if (!son[x])
            return;
        dfs2(son[x], topf);
        for (int i = head[x]; i; i = e[i].nxt) {
            int t = e[i].to;
            if (t == fa[x] || t == son[x])
                continue;
            dfs2(t, t);
        }
        return;
    }
    inline void push_up(int p) {
        maxx(p) = dep[maxx(p << 1)] < dep[maxx(p << 1 | 1)] ? maxx(p << 1) : maxx(p << 1 | 1);
        return;
    }
    inline void spread(int p) {
        if (add(p)) {
            maxx(p << 1) = dep[maxx(p << 1)] > dep[add(p)] ? maxx(p << 1) : add(p);
            maxx(p << 1 | 1) = dep[maxx(p << 1 | 1)] > dep[add(p)] ? maxx(p << 1 | 1) : add(p);
            add(p << 1) = dep[add(p << 1)] > dep[add(p)] ? add(p << 1) : add(p);
            add(p << 1 | 1) = dep[add(p << 1 | 1)] > dep[add(p)] ? add(p << 1 | 1) : add(p);
        }
        return add(p) = 0, void();
    }
    inline void build(int p, int l, int r) {
        l(p) = l;
        r(p) = r;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        build(p << 1, l, mid);
        build(p << 1 | 1, mid + 1, r);
        return push_up(p);
    }
    inline void change(int p, int l, int r, int d) {
        if (l <= l(p) && r(p) <= r) {
            maxx(p) = dep[maxx(p)] > dep[d] ? maxx(p) : d;
            add(p) = dep[add(p)] > dep[d] ? add(p) : d;
            return void();
        }
        spread(p);
        int mid = (l(p) + r(p)) >> 1;
        if (l <= mid)
            if (dep[d] > dep[maxx(p << 1)])
                change(p << 1, l, r, d);
        if (r > mid)
            if (dep[d] > dep[maxx(p << 1 | 1)])
                change(p << 1 | 1, l, r, d);
        return push_up(p);
    }
    inline int query(int p, int x) {
        if (l(p) == x && r(p) == x)
            return maxx(p);
        spread(p);
        int mid = (l(p) + r(p)) >> 1, ans = -1;
        if (x <= mid)
            return query(p << 1, x);
        else
            return query(p << 1 | 1, x);
    }
    signed main() {
        n = read(), T = read();
        for (int i = 1, u, v; i < n; ++i) u = read(), v = read(), adde(u, v);
        dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
        change(1, id[1], id[1] + sz[1] - 1, 1);
        while (T--) {
            string s;
            cin >> s;
            int x = read();
            if (s[0] == 'Q')
                printf("%lld
    ", query(1, id[x]));
            if (s[0] == 'C')
                change(1, id[x], id[x] + sz[x] - 1, x);
        }
        return 0;
    }
    }  // namespace yspm
    signed main() { return yspm::main(); 
    
    
  • 相关阅读:
    Ubuntu安装vsftp软件
    linux下LNMP环境安装笔记
    thinkphp在app接口开发过程中的通讯安全认证
    thinkphp在app接口开发过程中的通讯数据的封装
    thinkphp微信开发之jssdk拉取卡券及卡券的核销
    thinkphp微信开发之jssdk图片上传并下载到本地服务器
    用thinkphp进行微信开发的整体设计思考
    我常用的自定义函数之rmdir php删除目录及目录下的所有文件
    我常用的自定义函数之p 用于打印数据,调试代码很方便
    我常用的自定义函数之clean php自动过滤功能
  • 原文地址:https://www.cnblogs.com/yspm/p/12382273.html
Copyright © 2020-2023  润新知