• [洛谷]P1505 [国家集训队]旅游


    题目链接:

    传送门

    题目分析:

    树剖板,支持单点修改,区间取反,区间求最大值/最小值/和

    区间取反取两次等于没取,维护一个(rev tag),每次打标记用(xor)打,记录是否需要翻转,(push\_down)里判一下如果要取反就(-=2 * sum(p)),容易发现新最大值是原最小值的相反数,最小值同理

    细节挺多的,看代码

    代码:

    #include <bits/stdc++.h>
    #define N 2 * (200000 + 5)
    #define int long long
    #define INF (1000000000 + 7)
    using namespace std;
    inline int read() {
        int cnt = 0, f = 1; char c = getchar();
        while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
        while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
        return cnt * f;
    }
    int nxt[N], first[N], to[N], w[N], tot;
    void Add(int x, int y, int z) {
        nxt[++tot] = first[x];
        first[x] = tot;
        to[tot] = y;
        w[tot] = z;
    }
    int son[N], dep[N], top[N], siz[N], father[N], id[N], num[N], idx, a[N];
    void dfs1(int cur, int fa) {
        father[cur] = fa, siz[cur] = 1, dep[cur] = dep[fa] + 1;
        for (register int i = first[cur]; i; i = nxt[i]) {
            int v = to[i];
            if (v != fa) {
                a[v] = w[i];
                dfs1(v, cur);
                siz[cur] += siz[v];
                if (siz[son[cur]] < siz[v]) son[cur] = v;
            }
        }
    }
    
    void dfs2(int cur, int tp) {
        top[cur] = tp, num[cur] = ++idx, id[idx] = cur;
        if (son[cur]) dfs2(son[cur], tp);
        for (register int i = first[cur]; i; i = nxt[i]) {
            int v = to[i];
            if (!num[v]) dfs2(v, v);
        }
    }
    
    struct node {
        int l, r, Min, Max, sum, add;
        bool rev;
        #define l(p) tree[p].l
        #define r(p) tree[p].r
        #define Min(p) tree[p].Min
        #define Max(p) tree[p].Max
        #define sum(p) tree[p].sum
        #define rev(p) tree[p].rev
    }tree[N << 2];
    
    void push_up(int p) {
        sum(p) = sum(p << 1) + sum(p << 1 | 1);
        Max(p) = max(Max(p << 1), Max(p << 1 | 1));
        Min(p) = min(Min(p << 1), Min(p << 1 | 1));
    }
    
    void push_up_rev(int p) {
        int gmax = Max(p), gmin = Min(p);
        rev(p) ^= 1, sum(p) = -sum(p), Max(p) = -gmin, Min(p) = -gmax;
    }
    
    void push_down(int p) {
        if (rev(p)) {push_up_rev(p << 1), push_up_rev(p << 1 | 1), rev(p) ^= 1;}
    }
    
    void build_tree(int p, int l, int r) {
        l(p) = l, r(p) = r;
        if (l == r) {
            sum(p) = Max(p) = Min(p) = a[id[l]];
            return;
        }
        int mid = (l + r) >> 1;
        build_tree(p << 1, l, mid);
        build_tree(p << 1 | 1, mid + 1, r);
        push_up(p);
    }
    
    void modify(int p, int x, int d) {
        if (l(p) == r(p)) {
            rev(p) = 0, sum(p) = d, Max(p) = d, Min(p) = d;
            return;
        }
        push_down(p);
        int mid = (l(p) + r(p)) >> 1;
        if (x <= mid) modify(p << 1, x, d);
        else modify(p << 1 | 1, x, d);
        push_up(p);
    }
    
    void Reverse(int p, int l, int r) {
        if (l <= l(p) && r >= r(p)) {push_up_rev(p); return;}
        push_down(p);
        int mid = (l(p) + r(p)) >> 1;
        if (l <= mid) Reverse(p << 1, l, r);
        if (r > mid) Reverse(p << 1 | 1, l, r);
        push_up(p);
    }
    
    int query_sum(int p, int l, int r) {
        if (l <= l(p) && r >= r(p)) return sum(p);
        push_down(p);
        int mid = (l(p) + r(p)) >> 1;
        long long val = 0;
        if (l <= mid) val += query_sum(p << 1, l, r);
        if (r > mid) val += query_sum(p << 1 | 1, l, r);
        return val;
    }
    
    int query_max(int p, int l, int r) {
        if (l <= l(p) && r >= r(p)) return Max(p);
        push_down(p);
        int mid = (l(p) + r(p)) >> 1;
        long long val = -INF;
        if (l <= mid) val = max(val, query_max(p << 1, l, r));
        if (r > mid) val = max(val, query_max(p << 1 | 1, l, r));
        return val;
    }
    
    int query_min(int p, int l, int r) {
        if (l <= l(p) && r >= r(p)) return Min(p);
        push_down(p);
        int mid = (l(p) + r(p)) >> 1;
        long long val = INF;
        if (l <= mid) val = min(val, query_min(p << 1, l, r));
        if (r > mid) val = min(val, query_min(p << 1 | 1, l, r));
        return val;
    }
    
    void REVERSE (int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            Reverse(1, num[top[u]], num[u]);
            u = father[top[u]];
        }
        if (dep[u] < dep[v]) swap(u, v);
        Reverse(1, num[v] + 1, num[u]);
    }
    
    int Query_Sum (int u, int v) {
        long long val = 0;
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            val += query_sum(1, num[top[u]], num[u]);
            u = father[top[u]];
        }
        if (dep[u] < dep[v]) swap(u, v);
        val += query_sum(1, num[v] + 1, num[u]);
        return val;
    }
    
    int Query_Max (int u, int v) {
        long long val = -INF;
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            val = max(val, query_max(1, num[top[u]], num[u]));
            u = father[top[u]];
        }
        if (dep[u] < dep[v]) swap(u, v);
        val = max(val, query_max(1, num[v] + 1, num[u]));
        return val;
    }
    
    int Query_Min (int u, int v) {
        long long val = INF;
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            val = min(val, query_min(1, num[top[u]], num[u]));
            u = father[top[u]];
        }
        if (dep[u] < dep[v]) swap(u, v);
        val = min(val, query_min(1, num[v] + 1, num[u]));
        return val;
    }
    int n, m, u, v, x, y, z;
    char ope[10];
    void solve() {
        n = read();
        for (register int i = 1; i < n; i++) {
            x = read(); y = read(); z = read();
            Add(x + 1, y + 1, z); Add(y + 1, x + 1, z);
        }
        dfs1(1, 0); dfs2(1, 1); build_tree(1, 1, n);
        m = read();
        for (register int i = 1; i <= m; i++) {
            scanf("%s", ope + 1);
            x = read(); y = read();
            if (ope[1] == 'C') {
                u = to[2 * x - 1], v = to[2 * x];
                if (dep[u] < dep[v]) swap(u, v);
                modify(1, num[u], y);
            }
            if (ope[1] == 'N') {
                REVERSE (x + 1, y + 1);
            }
            if (ope[1] == 'S') {
                printf("%lld
    ", Query_Sum(x + 1, y + 1));
            }
            if (ope[1] == 'M') {
                if (ope[2] == 'A') printf("%lld
    ", Query_Max(x + 1, y + 1));
                else printf("%lld
    ", Query_Min(x + 1, y + 1));
            }
        }
    }
    
    signed main() {
    //	freopen("1.in","r",stdin);
        solve();
        return 0;
    }
    
  • 相关阅读:
    #最大公约数#CF346A Alice and Bob
    2020系统综合实践 第7次实践作业 5组
    第02组 ALPHA冲刺(2/4)
    第02组 Alpha冲刺(1/4)
    个人作业——软件工程实践总结作业
    个人作业——软件评测
    软件工程实践2019第五次作业——结对编程的编程实现
    软件工程实践2019第四次作业——结对编程的需求分析与原型模型设计
    软件工程实践2019第三次作业
    软件工程实践2019第二次作业
  • 原文地址:https://www.cnblogs.com/kma093/p/11154614.html
Copyright © 2020-2023  润新知