zoukankan      html  css  js  c++  java
  • [洛谷]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;
    }
    
  • 相关阅读:
    052 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 14 Eclipse下程序调试——debug2 多断点调试程序
    051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1
    050 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 12 continue语句
    049 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 11 break语句
    048 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 10 案例——阶乘的累加和
    047 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 09 嵌套while循环应用
    046 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 08 for循环的注意事项
    045 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 07 for循环应用及局部变量作用范围
    剑指OFFER----面试题04.二维数组中的查找
    剑指OFFER----面试题03. 数组中重复的数字
  • 原文地址:https://www.cnblogs.com/kma093/p/11154614.html
Copyright © 2011-2022 走看看