[hdu3966 Aragorn's Story]树链剖分

题意:要求在一棵N(<=50000)个带权节点的树上支持3种操作

(1)I u v w,u到v的路径上每个节点权值增加w

(2)D u v w,u到v的路径上每个节点权值减少w

(3)Q u,求u点的权值

思路:

将树剖分成若干条链,然后用区间数据结构来维护,这就是树链剖分。树链剖分后,这个题可以转化为一个“区间修改,单点查询”的问题,树状数组或线段树即可。

树状数组(1100ms):

#pragma comment(linker, "/STACK:10240000,10240000")

#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstring>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;

#ifndef ONLINE_JUDGE
    #include "local.h"
#endif

const int N = 5e4 + 7;
const int M = N;

namespace Edge {
    int last[N], to[M << 1], next[M << 1], cntE;
    void init() {
        cntE = 0;
        memset(last, -1, sizeof(last));
    }
    void addEdge(int u, int v) {
        to[cntE] = v;
        next[cntE] = last[u];
        last[u] = cntE ++;
    }
}

namespace TreeChain {
    int dep[N], top[N], w[N], son[N], siz[N], fa[N];
    int id[N], rnk[N], cntID;
    void init() {
        cntID = 0;
        memset(son, -1, sizeof(son));
    }
    void dfs1(int u, int f, int d) {
        dep[u] = d;
        fa[u] = f;
        siz[u] = 1;
        for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
            int v = Edge::to[i];
            if (v != f) {
                dfs1(v, u, d + 1);
                siz[u] += siz[v];
                if (son[u] == -1 || siz[v] > siz[son[u]])
                    son[u] = v;
            }
        }
    }
    void dfs2(int u, int t) {
        top[u] = t;
        id[u] = ++ cntID;
        rnk[id[u]] = u;
        if (son[u] == -1) return;
        dfs2(son[u], t);
        for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
            int v = Edge::to[i];
            if (v != son[u] && v != fa[u])
                dfs2(v, v);
        }
    }
}

int a[N];

namespace TreeArray {
    int c[N], n;
    void init(int n) {
        memset(c, 0, sizeof(c));
        TreeArray::n = n;
    }
    int lowbit(int x) { return x & -x; }
    void add(int p, int x) {
        while (p <= n) {
            c[p] += x;
            p += lowbit(p);
        }
    }
    void add(int l, int r, int x) {
        add(l, x);
        add(r + 1, -x);
    }
    int query(int p) {
        int ans = 0;
        while (p) {
            ans += c[p];
            p -= lowbit(p);
        }
        return ans;
    }
    void change(int u, int v, int w) {
        using namespace TreeChain;
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            add(id[top[u]], id[u], w);
            u = fa[top[u]];
        }
        if (dep[u] > dep[v]) swap(u, v);
        add(id[u], id[v], w);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    int n, m, p, u, v, w;
    char s[2];
    while (cin >> n >> m >> p) {
        Edge::init();
        TreeChain::init();
        for (int i = 1; i <= n; i ++) {
            scanf("%d", a + i);
        }
        for (int i = 0; i < m; i ++) {
            scanf("%d%d", &u, &v);
            Edge::addEdge(u, v);
            Edge::addEdge(v, u);
        }
        TreeChain::dfs1(1, 0, 0);
        TreeChain::dfs2(1, 1);
        TreeArray::init(n);
        for (int i = 1; i <= n; i ++) {
            TreeArray::add(i, i, a[TreeChain::rnk[i]]);
        }
        for (int i = 0; i < p; i ++) {
            scanf("%s", s);
            if (*s == 'Q') {
                scanf("%d", &u);
                printf("%d\n", TreeArray::query(TreeChain::id[u]));
            }
            else {
                scanf("%d%d%d", &u, &v, &w);
                if (*s == 'D') w = -w;
                TreeArray::change(u, v, w);
            }
        }
    }
    return 0;
}

线段树(1900ms):

#pragma comment(linker, "/STACK:10240000,10240000")

#include <iostream>
#include <cstdio>
#include <ctime>
#include <cstring>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;

#ifndef ONLINE_JUDGE
    #include "local.h"
#endif

const int N = 5e4 + 7;
const int M = N;

namespace Edge {
    int last[N], to[M << 1], next[M << 1], cntE;
    void init() {
        cntE = 0;
        memset(last, -1, sizeof(last));
    }
    void addEdge(int u, int v) {
        to[cntE] = v;
        next[cntE] = last[u];
        last[u] = cntE ++;
    }
}

namespace TreeChain {
    int dep[N], top[N], w[N], son[N], siz[N], fa[N];
    int id[N], rnk[N], cntID;
    void init() {
        cntID = 0;
        memset(son, -1, sizeof(son));
    }
    void dfs1(int u, int f, int d) {
        dep[u] = d;
        fa[u] = f;
        siz[u] = 1;
        for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
            int v = Edge::to[i];
            if (v != f) {
                dfs1(v, u, d + 1);
                siz[u] += siz[v];
                if (son[u] == -1 || siz[v] > siz[son[u]])
                    son[u] = v;
            }
        }
    }
    void dfs2(int u, int t) {
        top[u] = t;
        id[u] = ++ cntID;
        rnk[id[u]] = u;
        if (son[u] == -1) return;
        dfs2(son[u], t);
        for (int i = Edge::last[u]; ~i; i = Edge::next[i]) {
            int v = Edge::to[i];
            if (v != son[u] && v != fa[u])
                dfs2(v, v);
        }
    }
}

int a[N];

namespace SegTree {
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    int sum[N << 2], mark[N << 2];
    void up(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    void down(int rt, int len) {
        int rlen = len >> 1, llen = len - rlen;
        if (mark[rt]) {
            sum[rt << 1] += llen * mark[rt];
            mark[rt << 1] += mark[rt];
            sum[rt << 1 | 1] += rlen * mark[rt];
            mark[rt << 1 | 1] += mark[rt];
            mark[rt] = 0;
        }
    }
    void build(int l, int r, int rt) {
        mark[rt] = 0;
        if (l == r) {
            sum[rt] = a[TreeChain::rnk[l]];
            return;
        }
        int m = (l + r) >> 1;
        build(lson);
        build(rson);
        up(rt);
    }
    void update(int L, int R, int x, int l, int r, int rt) {
        if (L <= l && r <= R) {
            sum[rt] += (r - l + 1) * x;
            mark[rt] += x;
            return;
        }
        int m = (l + r) >> 1;
        down(rt, r - l + 1);
        if (L <= m) update(L, R, x, lson);
        if (R > m) update(L, R, x, rson);
        up(rt);
    }
    int query(int p, int l, int r, int rt) {
        if (l == r) return sum[rt];
        int m = (l + r) >> 1;
        down(rt, r - l + 1);
        if (p <= m) return query(p, lson);
        else return query(p, rson);
    }
    void change(int u, int v, int w, int n) {
        using namespace TreeChain;
        while (top[u] != top[v]) {
            if (dep[top[u]] < dep[top[v]]) swap(u, v);
            update(id[top[u]], id[u], w, 1, n, 1);
            u = fa[top[u]];
        }
        if (dep[u] > dep[v]) swap(u, v);
        update(id[u], id[v], w, 1, n, 1);
    }
    #undef lson
    #undef rson
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    int n, m, p, u, v, w;
    char s[2];
    while (cin >> n >> m >> p) {
        Edge::init();
        TreeChain::init();
        for (int i = 1; i <= n; i ++) {
            scanf("%d", a + i);
        }
        for (int i = 0; i < m; i ++) {
            scanf("%d%d", &u, &v);
            Edge::addEdge(u, v);
            Edge::addEdge(v, u);
        }
        TreeChain::dfs1(1, 0, 0);
        TreeChain::dfs2(1, 1);
        SegTree::build(1, n, 1);
        for (int i = 0; i < p; i ++) {
            scanf("%s", s);
            if (*s == 'Q') {
                scanf("%d", &u);
                printf("%d\n", SegTree::query(TreeChain::id[u], 1, n, 1));
            }
            else {
                scanf("%d%d%d", &u, &v, &w);
                if (*s == 'D') w = -w;
                SegTree::change(u, v, w, n);
            }
        }
    }
    return 0;
}

  

posted @ 2015-11-09 17:49  jklongint  阅读(307)  评论(0编辑  收藏  举报