hdu 3966 Aragorn's Story(树链剖分+树状数组)

题目链接:hdu 3966 Aragorn‘s Story

题目大意:给定一个棵树,然后三种操作

  • Q x:查询节点x的值
  • I x y w:节点x到y这条路径上所有节点的值增加w
  • D x y w:节点x到y这条路径上所有节点的值减少w

解题思路:树链剖分,用树状数组维护每个节点的值。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

#define lowbit(x) ((x)&(-x))
const int maxn = 50000;

int N, M, Q, val[maxn+5], fenw[maxn+5];
vector<int> g[maxn+5];

inline void add (int x, int v) {
    while (x <= N) {
        fenw[x] += v;
        x += lowbit(x);
    }
}

inline void add (int l, int r, int v) {
    add(l, v);
    add(r+1, -v);
}

inline int query (int x) {
    int ret = 0;
    while (x) {
        ret += fenw[x];
        x -= lowbit(x);
    }
    return ret;
}

int id, far[maxn+5], son[maxn+5], dep[maxn+5], cnt[maxn+5], top[maxn+5], idx[maxn+5];

void dfs_fir(int u, int pre, int d) {
    dep[u] = d;
    cnt[u] = 1;
    son[u] = 0;
    far[u] = pre;

    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == pre)
            continue;

        dfs_fir(v, u, d + 1);
        cnt[u] += cnt[v];
        if (cnt[son[u]] < cnt[v])
            son[u] = v;
    }
}

void dfs_sec(int u, int rot) {
    idx[u] = id++;
    top[u] = rot;

    if (son[u])
        dfs_sec(son[u], rot);

    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if (v == son[u] || v == far[u])
            continue;
        dfs_sec(v, v);
    }
}

void change (int u, int v, int c) {
    int p = top[u], q = top[v];
    while (p != q) {
        if (dep[p] < dep[q]) {
            swap(p, q);
            swap(u, v);
        }
        add(idx[p], idx[u], c);
        u = far[p];
        p = top[u];
    }

    /*
    if (dep[u] > dep[v]) swap(u, v);
    add(idx[u], idx[v], c);
    */
    if (dep[u] < dep[v]) swap(u, v);
    add(idx[v], idx[u], c);
}

int main () {
    while (scanf("%d%d%d", &N, &M, &Q) == 3) {
        id = 1;
        memset(fenw, 0, sizeof(fenw));
        for (int i = 1; i <= N; i++) {
            scanf("%d", &val[i]);
            g[i].clear();
        }

        int u, v, c;
        for (int i = 0; i < M; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
        }

        dfs_fir(1, -1, 0);
        dfs_sec(1, 1);

        for (int i = 1; i <= N; i++) add(idx[i], idx[i], val[i]);

        char op[5];
        while (Q--) {
            scanf("%s%d", op, &u);
            if (op[0] == ‘Q‘)
                printf("%d\n", query(idx[u]));
            else {
                scanf("%d%d", &v, &c);
                if (op[0] == ‘D‘) c = -c;
                change(u, v, c);
            }
        }
    }
    return 0;
}

hdu 3966 Aragorn's Story(树链剖分+树状数组)

时间: 2024-12-24 18:57:20

hdu 3966 Aragorn's Story(树链剖分+树状数组)的相关文章

HDU 5044 (树链剖分+树状数组+点/边改查)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变态树链剖分模板题.将以往树链剖分的点&边修改和查询合在一起之后,难度上去不少. 第一个卡人点是读入优化. 第二个卡人点是树状数组.由于要查询所有点,如果使用线段树,每次都要扫到底层才能取出点值,必T无疑. 然后使用树状数组之后,树链剖分的点/边修改写法有些变动. 点查询变化不大. 边查询只要查询一下

bzoj1146整体二分+树链剖分+树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1,ch=getchar(); 9 while(ch<

树链剖分 树的统计

/*题目描述 Description一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I.                    CHANGE u t : 把结点u的权值改为tII.                 QMAX u v: 询问从点u到点v的路径上的节点的最大权值III.               QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身 输入描述 In

BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. 时间复杂度O(N*log^3(N)) ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<

Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组

Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other. The boys decided to h

POJ 2763 Housewife Wind(树链剖分+树状数组)

[题目链接] http://poj.org/problem?id=2763 [题目大意] 在一棵树上,给出一些边的边长,有修改边的边长的操作, 询问每次从当前点到目标点的最短距离 [题解] 树链剖分之后,相当于树状数组的单点更新和区间查询, 注意边权转点权之后链操作不覆盖deep最浅的点,这里容易出错 [代码] #include <cstdio> #include <cstring> #include <algorithm> using namespace std; c

【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】

模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: -------------------------------------------------------------------------------- [ 3 ]  上面都不是重点--重点是树状数组的区间修改+区间查询 这个很好玩 其实也挺简单 首先依旧是引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delt

(简单) POJ 3321 Apple Tree,树链剖分+树状数组。

Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by branches.

Codeforces Round #425 (Div. 2) D 树链剖分 + 树状数组维护区间

一看就知道 可以LCA判断做 也可以树链剖分拿头暴力 然而快速读入和线段树维护区间会T70 于是只能LCA? 线段树的常数不小 于是需要另外一种办法来进行区间加减和查询区间和 就是使用树状数组 这个题的代码 #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<vector> #include<cstring> using na