zoukankan      html  css  js  c++  java
  • HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树

    HDU 3966 Aragorn's Story

    先把树剖成链,然后用树状数组维护:

    讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇...

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    using namespace std;
    const int MAXN = 50010;
    
    struct Edge
    {
        int to,next;
    }edge[MAXN*2];
    
    int head[MAXN],tot;
    int top[MAXN];
    int fa[MAXN];
    int deep[MAXN];
    int num[MAXN];
    int p[MAXN];
    int fp[MAXN];
    int son[MAXN];
    int pos;
    
    void init()
    {
        tot = 0;
        memset(head,-1,sizeof(head));
        pos = 1;//使用树状数组,编号从头1开始
        memset(son,-1,sizeof(son));
    }
    
    void addedge(int u,int v)
    {
        edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++;
    }
    
    void dfs1(int u,int pre,int d)
    {
        deep[u] = d;
        fa[u] = pre;
        num[u] = 1;
        for(int i = head[u];i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(v != pre)
            {
                dfs1(v,u,d+1);
                num[u] += num[v];
                if(son[u] == -1 || num[v] > num[son[u]])
                    son[u] = v;
            }
        }
    }
    
    void getpos(int u,int sp)
    {
        top[u] = sp;
        p[u] = pos++;
        fp[p[u]] = u;
        if(son[u] == -1) return;
        getpos(son[u],sp);
        for(int i = head[u];i != -1;i = edge[i].next)
        {
            int v = edge[i].to;
            if( v != son[u] && v != fa[u])
                getpos(v,v);
        }
    }
    
    //树状数组
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    int c[MAXN];
    int n;
    
    int sum(int i)
    {
        int s = 0;
        while(i > 0)
        {
            s += c[i];
            i -= lowbit(i);
        }
        return s;
    }
    
    void add(int i,int val)
    {
        while(i <= n)
        {
            c[i] += val;
            i += lowbit(i);
        }
    }
    
    void Change(int u,int v,int val)//u->v的路径上点的值改变val
    {
        int f1 = top[u], f2 = top[v];
        int tmp = 0;
        while(f1 != f2)
        {
            if(deep[f1] < deep[f2])
            {
                swap(f1,f2);
                swap(u,v);
            }
            add(p[f1],val);
            add(p[u]+1,-val);
            u = fa[f1];
            f1 = top[u];
        }
        if(deep[u] > deep[v]) swap(u,v);
        add(p[u],val);
        add(p[v]+1,-val);
    }
    
    int a[MAXN];
    
    int main()
    {
        int M,P;
        while(scanf("%d%d%d",&n,&M,&P) == 3)
        {
            int u,v;
            int C1,C2,K;
            char op[10];
            init();
            for(int i = 1;i <= n;i++)
            {
                scanf("%d",&a[i]);
            }
            while(M--)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
            }
            dfs1(1,0,0);
            getpos(1,1);
            memset(c,0,sizeof(c));
    
            for(int i = 1;i <= n;i++)
            {
                add(p[i],a[i]);
                add(p[i]+1,-a[i]);
            }
            while(P--)
            {
                scanf("%s",op);
                if(op[0] == 'Q')
                {
                    scanf("%d",&u);
                    printf("%d
    ",sum(p[u]));
                }
                else
                {
                    scanf("%d%d%d",&C1,&C2,&K);
                    if(op[0] == 'D')
                        K = -K;
                    Change(C1,C2,K);
                }
            }
        }
        return 0;
    }
    View Code

    或者用线段树维护:

    要注意,点权的时候,update函数里是不能 if (u == v) return;的。T_T

    // HDU 3966
    
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #define maxn 50010
    #include <vector>
    using namespace std;
    
    int a[maxn];
    vector<int> edge[maxn];
    
    int pos;
    int top[maxn];
    int fa[maxn];
    int deep[maxn];
    
    int num[maxn];
    int p[maxn];
    int fp[maxn];
    int son[maxn];
    
    //树链剖分
    void dfs1(int u, int pre, int d) { // fa num deep
        deep[u] = d;
        fa[u] = pre;
        num[u] = 1;
        for (int i=0; i<edge[u].size(); ++i) {
            int v = edge[u][i];
            if (v != pre) {
                dfs1(v, u, d+1);
                num[u] += num[v];
                if (son[u] == -1 || num[v] > num[son[u]]) {
                    son[u] = v;
                }
            }
        }
    }
    
    void dfs2(int u, int sp) {
        top[u] = sp;
        p[u] = pos++;
        fp[p[u]] = u;
        if (son[u] == -1) return;
        dfs2(son[u], sp);
        for (int i=0; i<edge[u].size(); ++i) {
            int v = edge[u][i];
            if (v != son[u] && v != fa[u])
                dfs2(v, v);
        }
    }
    
    //线段树
    struct Node {
        int l, r;
        int val;
        int mark;
    }segTree[maxn*3];
    
    void build(int rt, int l, int r) {
        segTree[rt].l = l;
        segTree[rt].r = r;
        segTree[rt].mark = 0;
        segTree[rt].val = 0;
        if (l == r) {
            segTree[rt].val = a[fp[l] - 1];
            return;
        }
        int mid = (l + r) / 2;
        build(rt<<1, l, mid);
        build((rt<<1)|1, mid+1, r);
    }
    
    void push_down(int rt) {
        if (segTree[rt].mark != 0) {
            segTree[rt].val += segTree[rt].mark;
            if (segTree[rt].l != segTree[rt].r) {
                segTree[rt<<1].mark += segTree[rt].mark;
                segTree[(rt<<1)|1].mark += segTree[rt].mark;
            }
            segTree[rt].mark = 0;
        }
    }
    
    void update_seg(int rt, int l, int r, int val) { // 把线段树的[l, r] 区间的值+val
        push_down(rt);
        if (segTree[rt].l >= l && segTree[rt].r <= r) {
            segTree[rt].mark += val;
            push_down(rt);
            return;
        }
        int mid = (segTree[rt].l + segTree[rt].r) / 2;
        if (r <= mid) update_seg(rt<<1, l, r, val);
        else if (l > mid) update_seg((rt<<1)|1, l, r, val);
        else {
            update_seg(rt<<1, l, mid, val);
            update_seg((rt<<1)|1, mid+1, r, val);
        }
    }
    
    void update(int u, int v, int w) { // u 到 v结点的路上的值增加 val
        int f1 = top[u];
        int f2 = top[v];
        while(f1 != f2) {
            if (deep[f1] < deep[f2]) {
                swap(f1, f2);
                swap(u, v);
            }
            update_seg(1, p[f1], p[u], w);
            u = fa[f1], f1 = top[u];
        }
    //    if (u == v) return;
        if (deep[u] > deep[v]) swap(u, v);
        update_seg(1, p[u], p[v], w);
    }
    
    int query_seg(int rt, int los) { //查询线段树 los处的值
        push_down(rt);
        if (segTree[rt].l == segTree[rt].r && segTree[rt].r == los) {
            return segTree[rt].val;
        }
        int mid = (segTree[rt].l + segTree[rt].r) / 2;
        if (los <= mid) return query_seg(rt<<1, los);
        else if (los > mid) return query_seg((rt<<1)|1, los);
    }
    
    int query(int u) { // 询问u点处的值
        return query_seg(1, p[u]);
    }
    
    int n;
    
    void init() {
        pos = 0;
        memset(son, -1, sizeof(son));
        for (int i=1; i<=n; ++i) {
            edge[i].clear();
        }
    }
    
    
    int main() {
    //    freopen("in.cpp", "r", stdin);
        int m, pp;
        while(~scanf("%d%d%d", &n, &m, &pp)) {
            init();
            for (int i=0; i<n; ++i) {
                scanf("%d", &a[i]);
            }
            for (int i=0; i<m; ++i) {
                int a, b;
                scanf("%d%d", &a, &b);
                edge[a].push_back(b);
                edge[b].push_back(a);
            }
    
            dfs1(1, 0, 1);
            dfs2(1, 1);
            build(1, 0, pos-1);
    
            for (int i=0; i<pp; ++i) {
                char op[10];
                int u, v, w;
                scanf("%s", op);
                if (op[0] == 'I' || op[0] == 'D') {
                    scanf("%d%d%d", &u, &v, &w);
                    if (op[0] == 'D') w = -w;
                    update(u, v, w);
                }else {
                    scanf("%d", &u);
                    int ans = query(u);
                    printf("%d
    ", ans);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    P1001 A+B Problem
    NOIP2015D1T2 信息传递
    海淀区赛游记。。。。
    P3375 【模板】KMP字符串匹配
    Print Article HDU
    BZOJ-2-4870: [Shoi2017]组合数问题 矩阵优化 DP
    BZOJ-1- 4868: [Shoi2017]期末考试-三分
    #6164. 「美团 CodeM 初赛 Round A」数列互质-莫队
    湖南大学第十四届ACM程序设计新生杯(重现赛)
    Codeforces Round #530 (Div. 2)
  • 原文地址:https://www.cnblogs.com/icode-girl/p/6040827.html
Copyright © 2011-2022 走看看