HDU 3966 Aragorn's Story(树链剖分)

来源:互联网 发布:高端 商务礼品 知乎 编辑:程序博客网 时间:2024/06/16 01:02

好久没有打线段树了。。

题意

更新树上的一段路径,查询某个点/路径的权值

思路

树链剖分模版题,树链剖分将一棵树转化成多条重链,将树的问题变成区间问题
这里写图片描述
如图,加粗的是重链,打红点的是链的根节点

代码

#include <bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define rep(i,a,b) for(int i=a;i<b;i++)const int INF = 0x3f3f3f3f;const int maxn = 5e4 + 50;const int mod = 1e9 + 7;const double eps = 1e-8;typedef long long ll;using namespace std;struct SegmentTree;struct Edge {    int u, v;    Edge() {}    Edge(int u, int v) : u(u), v(v) {}};//第一遍DFS找出所有重边//重边:连接最大子树的边//第二遍DFS连接重链struct TreePartition {    vector<Edge> edges;    vector<int> G[maxn];    int siz[maxn]; //子树节点个数    int top[maxn]; //链顶端节点    int son[maxn]; //重儿子    int dep[maxn]; //深度    int tid[maxn]; //剖分后编号    int rnk[maxn];//节点在线段树中的位置    int fa[maxn]; // 父节点    int n, m;    int tim;    void init(int n) {        this->n = n;        edges.clear();        rep(i, 0, n + 1) G[i].clear();        mem(son, -1); tim = 0;    }    void addEdge(int u, int v) {        edges.push_back(Edge(u, v));        m = edges.size();        G[u].push_back(m - 1);    }    void dfs1(int u, int pa, int depth) {        dep[u] = depth;        fa[u] = pa;        siz[u] = 1;        int sz = G[u].size();        for (int i = 0; i<sz; i++) {            Edge &e = edges[G[u][i]];            int v = e.v;            if (v != pa) {                dfs1(v, u, depth + 1);                siz[u] += siz[v];                if (son[u] == -1                    || siz[v]>siz[son[u]])                    son[u] = v;            }        }    }    void dfs2(int u, int tp) {        top[u] = tp;        tid[u] = ++tim;        rnk[tid[u]] = u;        if (son[u] == -1) return;        dfs2(son[u], tp);        int sz = G[u].size();        for (int i = 0; i<sz; i++) {            Edge &e = edges[G[u][i]];            int v = e.v;            if (v != son[u] && v != fa[u])                dfs2(v, v);        }    }    void build(int rt) {        dfs1(rt, -1, 0);        dfs2(rt, rt);    }};#define lson(x) (x<<1)#define rson(x) (x<<1|1)#define lhs l,m,lson(rt)#define rhs m+1,r,rson(rt)int s[maxn];struct SegmentTree {    int sum[maxn << 2], mark[maxn << 2];    inline void pushUp(int rt) {        sum[rt] = sum[lson(rt)] + sum[rson(rt)];    }    inline void pushDown(int rt, int len) {        if (mark[rt]) {            mark[lson(rt)] += mark[rt];            mark[rson(rt)] += mark[rt];            sum[lson(rt)] += mark[rt] * (len - len / 2);            sum[rson(rt)] += mark[rt] * (len / 2);            mark[rt] = 0;        }    }    void build(int l, int r, int rt) {        mark[rt] = 0;        if (l == r) sum[rt] = s[l];        else {            int m = (l + r) >> 1;            build(lhs);            build(rhs);            pushUp(rt);        }    }    void update(int L, int R, int add, int l, int r, int rt) {        int len = r - l + 1;        if (L <= l && R >= r) {            mark[rt] += add;            sum[rt] += (ll)add*len;            return;        }        pushDown(rt, len);        int m = (l + r) >> 1;        if (L <= m) update(L, R, add, lhs);        if (R>m) update(L, R, add, rhs);        pushUp(rt);    }    int query(int L, int R, int l, int r, int rt) {        if (L <= l && R >= r) return sum[rt];        pushDown(rt, r - l + 1);        int m = (l + r) >> 1;        int ret = 0;        if (L <= m) ret += query(L, R, lhs);        if (R>m) ret += query(L, R, rhs);        return ret;    }};SegmentTree st;TreePartition tp;int n, m, q;//更新链,查询点/链void changeLine(int x, int y, int add) {    while (tp.top[x] != tp.top[y]) {        if (tp.dep[tp.top[x]]<tp.dep[tp.top[y]]) swap(x, y);        st.update(tp.tid[tp.top[x]], tp.tid[x], add, 1, n, 1);        x = tp.fa[tp.top[x]];    }    if (tp.dep[x]>tp.dep[y]) swap(x, y);    st.update(tp.tid[x], tp.tid[y], add, 1, n, 1);}int ts[maxn];int main(){#ifndef ONLINE_JUDGE    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);#endif    while (~scanf("%d %d %d", &n, &m, &q)) {        rep(i, 1, n + 1) scanf("%d", &ts[i]);        tp.init(n);        int u, v; char buf[10];        rep(i, 0, m) {            scanf("%d %d", &u, &v);            tp.addEdge(u, v);            tp.addEdge(v, u);        }        tp.build(1);        //Important!!        rep(i, 1, n + 1) s[i] = ts[tp.rnk[i]];        st.build(1, n, 1);        scanf("%d", &q);        rep(i, 0, q) {            scanf(" %s", buf);            if (buf[0] != 'Q') {                int add;                scanf("%d %d %d", &u, &v, &add);                if (buf[0] == 'D') add = -add;                changeLine(u, v, add);            }            else {                scanf("%d", &u);                printf("%d\n", st.query(tp.tid[u], tp.tid[u], 1, n, 1));            }         }    }    return 0;}
0 0