zoukankan      html  css  js  c++  java
  • cf 383C Propagating tree

    传送门

    只能说这题很妙。

    给出一棵树,树上有权值,现在你对一个结点加(x),那么他的孩子结点会加(-x),依次类推。

    操作有单点加,单点查询。

    实际上可以把树按照深度划分为奇和偶。定义奇数的加,偶数的减。

    如果说深度为奇数,那么就把它的所有孩子结点都加(x),如果说深度为偶数,那么就把它的所有孩子结点都加(-x)
    查询时,同样这样,如果深度是奇数,那么就把答案乘1,否则乘-1。

    对于深度为偶数的,加的时候是负数,查询的时候再乘以负号,答案不变。如果有贡献是由深度为奇数的加上的,那么加的一定是正数,最后乘负号,答案不变。
    同理,对于深度为奇数的,加的时候是正数,查询的时候是正数。如果有贡献来自深度为偶数的,那么加的值肯定是负数。

    相当于变成了线段树区间加操作和单点查询操作了。

    树上线段树操作,可以用树链剖分,但是大材小用了,就直接利用dfs序+线段树即可。

    #include <bits/stdc++.h>
    #define ll long long
    #define CASE int Kase = 0; cin >> Kase; for(int kase = 1; kase <= Kase; kase++)
    using namespace std;
    template<typename T = long long> inline T read() {
        T s = 0, f = 1; char ch = getchar();
        while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();} 
        return s * f;
    }
    const int N = 2e5 + 5, M = 1e6 + 5, MOD = 1e9 + 7, CM = 998244353, INF = 0x3f3f3f3f;
    struct Edge {
        int to, next;
    }e[M << 1];
    int head[N], tot;
    void add(int u, int v){
        e[++tot].to = v;
        e[tot].next = head[u];
        head[u] = tot;
    }
    int a[N];
    struct SegTree{
        struct Node{
            int l, r;
            int val, lazy;
            #define l(p) tree[p].l
            #define r(p) tree[p].r
            #define lson (p << 1)
            #define rson (p << 1 | 1)
            #define val(p) tree[p].val
            #define lazy(p) tree[p].lazy
        } tree[N << 2];
        void pushup(int p){
            val(p) = val(lson) + val(rson);
        }
        void pushdown(int p){
            if(lazy(p)) {
                lazy(lson) += lazy(p);
                lazy(rson) += lazy(p);
                val(lson) += (r(lson) - l(lson) + 1) * lazy(p);
                val(rson) += (r(rson) - l(rson) + 1) * lazy(p);
                lazy(p) = 0;
            }
        }
        void build(int p, int l, int r){
            l(p) = l, r(p) = r;
            lazy(p) = 0, val(p) = 0;
            if(l(p) == r(p)) {
                return;
            }
            int mid = (l + r) >> 1;
            build(lson, l, mid); build(rson, mid + 1, r);
            pushup(p);
        }
        void Change(int p, int l, int r, int x) {
            if(l <= l(p) && r(p) <= r) {
                lazy(p) += x;
                val(p) += (r(p) - l(p) + 1) * x;
                return;
            }
            pushdown(p);
            int mid = (l(p) + r(p)) >> 1;
            if(l <= mid) Change(lson, l, r, x);
            if(r > mid) Change(rson, l, r, x);
            pushup(p);
        }
        int Query(int p, int x) {
            if(l(p) == r(p)) return val(p);
            pushdown(p);
            int mid = (l(p) + r(p)) >> 1;
            if(x <= mid) return Query(lson, x);
            else return Query(rson, x);
        }
    } seg;
    int dep[N], l[N], r[N], id;
    void dfs(int u, int fath){
        dep[u] = dep[fath] + 1; l[u] = ++id;
        for(int i = head[u]; i; i = e[i].next) {
            int v = e[i].to;
            if(v == fath) continue;
            dfs(v, u);
        }
        r[u] = id;
    }
    void subtask1() {
        int x = read(), val = read();
        seg.Change(1, l[x], r[x], dep[x] & 1 ? val : -val);
    }
    void subtask2() {
        int x = read();
        printf("%d
    ", a[x] + seg.Query(1, l[x]) * (dep[x] & 1 ? 1 : -1));
    }
    void solve(int kase){
        int n = read(), m = read();
        for(int i = 1; i <= n; i++) a[i] = read();
        for(int i = 1; i < n; i++) {
            int u = read(), v = read();
            add(u, v); add(v, u);
        }
        dfs(1, 0);
        seg.build(1, 1, n);
        for(int i = 1; i <= m; i++) {
            int op = read();
            if(op == 1) subtask1();
            if(op == 2) subtask2();
        }
    }
    const bool DUO = 0;
    int main(){
        clock_t start, finish; double totaltime; start = clock();
        if(DUO) {CASE solve(kase);} else solve(1);
        finish = clock(); 
        #ifdef ONLINE_JUDGE
            return 0;
        #endif
        printf("
    Time: %lfms
    ", (double)(finish - start) / CLOCKS_PER_SEC * 1000);
        return 0;
    }
    
    I‘m Stein, welcome to my blog
  • 相关阅读:
    C#遍历List并删除某个或者几个元素的方法
    7月清北学堂培训 Day 4
    7月清北学堂培训 Day 3
    7月清北学堂培训 Day 2
    7月清北学堂培训 Day 1
    P1383 高级打字机
    P2401 不等数列
    P1412 经营与开发
    P1314 聪明的质监员
    2019.7.9 校内测试 T3 15数码问题
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14402270.html
Copyright © 2011-2022 走看看