HDU-4918 Query on the subtree(树分治+树状数组)

来源:互联网 发布:淘宝官方优惠券app 编辑:程序博客网 时间:2024/05/21 17:38

Query on the subtree

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1193    Accepted Submission(s): 375


Problem Description
bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. At the very begining, the i-th vertex is assigned with weight wi.

There are q operations. Each operations are of the following 2 types:

Change the weight of vertex v into x (denoted as "! v x"),
Ask the total weight of vertices whose distance are no more than d away from vertex v (denoted as "? v d").

Note that the distance between vertex u and v is the number of edges on the shortest path between them.
 

Input
The input consists of several tests. For each tests:

The first line contains n,q (1≤n,q≤105). The second line contains n integers w1,w2,…,wn (0≤wi≤104). Each of the following (n - 1) lines contain 2 integers ai,bi denoting an edge between vertices ai and bi (1≤ai,bi≤n). Each of the following q lines contain the operations (1≤v≤n,0≤x≤104,0≤d≤n).
 

Output
For each tests:

For each queries, a single number denotes the total weight.
 

Sample Input
4 31 1 1 11 22 33 4? 2 1! 1 0? 2 13 31 2 31 21 3? 1 0? 1 1? 1 2
 

Sample Output
32166

题解:树分治+树状数组

首先看到询问任意点对的距离不超过d就想到用树分治来写,通过不断找重心将树划分,递归层数不会超过logN。如果不进行修改操作,我们就只要用数组cnt[u][dis]储存到点u距离小于dis的权值和。

但是现在需要进行修改,因此需要用数据结构来维护:对于一个点u,他最多只属于logN个子树,也就是最多只属于logN个重心。所以我们可以预处理出每个点所属于的重心(这个可以在树分治时完成)以及到这些重心的距离,以每个重心建树状数组,每个点按照到重心的距离插入到树状数组中,然后每次查询到u距离不超过d的点的个数就通过树状数组求前缀和得到。

假设子树的重心为root,对于这颗子树的一个节点v,设subroot是root的子节点且是v的根节点,那么到u距离不超过d的点的个数为:T[root].sum[d-dis]-T[subroot].sum[d-dis]

关于这道题,鸟神的博客写的超级棒:点击打开链接

#include<bits/stdc++.h>using namespace std;typedef long long LL;const int MX = 1e5 + 5;const int MXM = 4e6 + 5;const int INF = 0x3f3f3f3f;struct Edge {    int v, nxt;} E[MX * 2];int head[MX], rear;int fir[MX], tot;int sz[MX], maxv[MX], dep[MX],  id[MX];int val[MX], vis[MX], n, cnt, Max, root;void init() {    memset(vis, 0, sizeof(vis));    memset(head, -1, sizeof(head));    memset(fir, -1, sizeof(fir));    rear = cnt = tot = 0;}void add(int u, int v) {    E[rear].v = v;    E[rear].nxt = head[u];    head[u] = rear++;}struct Tree {    int n ;    vector < int > T ;    void init (int sz) {        T.clear();        n = sz;        T.resize(n + 1);    }    void add (int x, int v) {        for (int i = x; i <= n; i += i & -i) T[i] += v;    }    int sum (int x) {        if (x > n) x = n;        int ret = 0;        for (int i = x; i > 0; i -= i & -i) ret += T[i];        return ret;    }} T[MX << 1];//类似于领接表,node记录包含u的所有根节点以及根节点的子树struct node {    int root, subroot; //根节点,根节点的子节点    int dis, nxt;} Node[MXM];void add_node(int u, int root, int subroot, int dis) {    Node[tot].root = root;    Node[tot].subroot = subroot;    Node[tot].dis = dis;    Node[tot].nxt = fir[u];    fir[u] = tot++;}void dfs_size(int u, int fa) {    sz[u] = 1; maxv[u] = 0;    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v] || v == fa) continue;        dfs_size(v, u);        sz[u] += sz[v];        maxv[u] = max(maxv[u], sz[v]);    }}void dfs_root(int u, int fa, int rt) {    maxv[u] = max(maxv[u], sz[rt] - sz[u]);    if (maxv[u] < Max) {        Max = maxv[u];        root = u;    }    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v] || v == fa) continue;        dfs_root(v, u, rt);    }}void dfs_deep(int u, int fa, int deep, int root, int subroot) {    dep[u] = deep;    T[root].add(dep[u], val[u]);    T[subroot].add(dep[u], val[u]);    add_node(u, root, subroot, dep[u]);    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v] || v == fa) continue;        dfs_deep(v, u, deep + 1, root, subroot);    }}void DFS(int u) {    Max = n;    dfs_size(u, -1); dfs_root(u, -1, u);    int rt = root; id[rt] = ++cnt;    vis[rt] = 1;    dep[rt] = 1;  //设根节点深度为1    T[cnt].init(sz[u] + 1);    T[cnt].add(1, val[rt]);    add_node(rt, id[rt], 0, 1);    for (int i = head[rt]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v]) continue;        T[++cnt].init(sz[v] + 1);        dfs_deep(v, rt, 2, id[rt], cnt);    }    for (int i = head[rt]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v]) continue;        DFS(v);    }}int main() {    int m;    //freopen("in.txt","r",stdin);    while (~scanf("%d%d", &n, &m)) {        init();        for (int i = 1; i <= n; i++) scanf("%d", &val[i]);        for (int i = 1, u, v; i < n; i++) {            scanf("%d%d", &u, &v);            add(u, v); add(v, u);        }        DFS(1);        char op[5]; int u, x;        while (m--) {            scanf("%s%d%d", op, &u, &x);            if (op[0] == '!') {                for (int i = fir[u]; ~i; i = Node[i].nxt) {                    int root = Node[i].root, subroot = Node[i].subroot, dis = Node[i].dis;                    T[root].add(dis, x - val[u]);                    if (subroot) T[subroot].add(dis, x - val[u]);                }                val[u] = x;            } else {                int ans = 0;                for (int i = fir[u]; ~i; i = Node[i].nxt) {                    int root = Node[i].root, subroot = Node[i].subroot, dis = Node[i].dis - 1;                    ans += T[root].sum(x - dis + 1);                    if (subroot) ans -= T[subroot].sum(x - dis + 1);                }                printf("%d\n", ans);            }        }    }    return 0;}


阅读全文
0 0