HDU 3966-Aragorn's Story 树链剖分+树状数组

题目链接


题意:有一棵树,每个节点有权值
有三种操作:

  • I c1 c2 k 从节点c1到节点c2的路径上每个节点权值增加k
  • D c1 c2 k 从节点c1到节点c2的路径上每个节点权值减少k
  • Q i 查询节点i的权值是多少

思路:

  • 树链剖分处理出来的链放在数组中,使用树状数组维护
  • 树状数组进行区间修改,单点查询

树状数组区间修改,单点查询的方法:链接


#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#include <stack>
#include <string>
#include <math.h>
#include <bitset>
#include <ctype.h>
#define CLR(n,b) memset(n, b, sizeof(n))
using namespace std;
typedef pair<int,int> P;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-9;
const int N = 6e4 + 5;
const int mod = 1e9 + 7;
struct Edge
{
    int u,v;
    Edge() {}
    Edge(int a, int b): u(a), v(b) {}
};
int fa[N],son[N], p[N],fp[N], top[N],dep[N],sz[N];
int pos;
int n,m,k;
vector<Edge> edges;
vector<int> G[N];
void init(int n)
{
    CLR(fa, 0);  CLR(son, -1); CLR(p, -1);
    CLR(fp, -1); CLR(top, 0); CLR(sz, 0); CLR(dep, 0);
    pos = 0; edges.clear();
    for(int i = 0; i <= n; i++) G[i].clear();
}
void addedge(int u, int v)
{
    edges.push_back(Edge(u,v));
    edges.push_back(Edge(v,u));
    int m = edges.size();
    G[u].push_back(m-2);
    G[v].push_back(m-1);
}

// 树链剖分

void dfs(int u, int pre, int d)
{
    fa[u] = pre;
    dep[u] = d;
    sz[u] = 1;
    son[u] = -1;
    for(int i = 0; i < G[u].size(); i++)
    {
        Edge &e = edges[G[u][i]];
        int v = e.v;
        if(v == pre) continue;
        dfs(v, u, d+1);
        sz[u] += sz[v];
        if(son[u] == -1 || sz[son[u]] < sz[v])
            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 = 0; i < G[u].size(); i++)
    {
        Edge &e = edges[G[u][i]];
        int v = e.v;
        if(v == son[u] || v == fa[u]) continue;
        getpos(v, v);
    }
}

// 树状数组
int c[N];
inline int lowbit(int x)
{
    return x&(-x);
}
void add(int x, int val)
{
    while(x <= n)
    {
        c[x] += val;
        x += lowbit(x);
    }
}
int sum(int x)
{
    int ans = 0;
    while(x)
    {
        ans += c[x];
        x -= lowbit(x);
    }
    return ans;
}

// change
void change(int x, int y, int val)
{
    int u = x, v = y;
    int f1 = top[u], f2 = top[v];
    while(f1 != f2)
    {
        if(dep[f1] < dep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        add(p[f1], val);
        add(p[u]+1, -val);
        u = fa[f1];
        f1 =top[u];
    }

    if(dep[u] > dep[v]) swap(u,v);
    add(p[u], val);
    add(p[v]+1, -val);
}

int a[N];
int main()
{
    while(~scanf("%d%d%d", &n, &m, &k))
    {
        init(n);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
        }
        for(int i = 0; i < m; i++)
        {
            int u,v;
            scanf("%d%d", &u, &v);
            addedge(u,v);
        }
        dfs(1,1,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(k--)
        {
            char cmd[10];
            int x,y,z;
            scanf("%s", cmd);
            if(cmd[0] == 'Q')
            {
                scanf("%d", &x);
                printf("%d\n", sum(p[x]));
            }
            else
            {
                scanf("%d%d%d", &x,&y,&z);
                if(cmd[0] == 'D')
                    z = -z;
                change(x,y,z);
            }
        }
    }

    return 0;
}
posted @ 2017-09-07 22:42  可达龙  阅读(160)  评论(0编辑  收藏  举报