HAOI2015 树上操作

时间:2024-01-14 18:42:26

HAOI2015 树上操作

题目描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入输出格式

输入格式:

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

输出格式:

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

输入输出样例

输入样例#1:
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
输出样例#1:
6
9
13

说明

对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

会超过 10^6 。

模板题就不多说啦,http://blog.sina.com.cn/s/blog_6974c8b20100zc61.html 有介绍,我就是看这个懂得

#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 100000 + 10;
int cnt = 0,n,m,map[maxn],val[maxn],num[maxn],size[maxn],father[maxn],son[maxn],top[maxn],dep[maxn],w[maxn];
vector<int> edges[maxn];
inline void dfs1(int now,int f) {
    size[now] = 1;
    father[now] = f;
    dep[now] = dep[father[now]]+1;
    for (size_t i = 0;i < edges[now].size();i++)
        if (edges[now][i] != f) {
            dfs1(edges[now][i],now);
            size[now] += size[edges[now][i]];
            if (size[son[now]] < size[edges[now][i]] || !son[now]) son[now] = edges[now][i];
        }
}
inline void dfs2(int now,int ntop) {
    top[now] = ntop;
    num[now] = ++cnt;
    map[num[now]] = now;
    if (son[now]) dfs2(son[now],ntop);
    for (size_t i = 0;i < edges[now].size();i++)
        if (edges[now][i] != father[now] && edges[now][i] != son[now]) dfs2(edges[now][i],edges[now][i]);
}
struct seg { long long sum,mark,l,r; } tree[maxn*4];
inline void BuildTree(int l,int r,int root) {
    if (l == r) {
        tree[root].l = l;
        tree[root].r = r;
        tree[root].sum = val[map[l]];
        tree[root].mark = 0;
        return;
    }
    int mid = l+r>>1;
    BuildTree(l,mid,root<<1);
    BuildTree(mid+1,r,(root<<1)+1);
    tree[root].l = l;
    tree[root].r = r;
    tree[root].mark = 0;
    tree[root].sum = tree[root<<1].sum+tree[(root<<1)+1].sum;
}
inline void pushdown(int root) {
    if (tree[root].mark) {
        tree[root<<1].mark += tree[root].mark;
        tree[root<<1|1].mark += tree[root].mark;
        tree[root<<1].sum += tree[root].mark*(tree[root<<1].r-tree[root<<1].l+1);
        tree[root<<1|1].sum += tree[root].mark*(tree[root<<1|1].r-tree[root<<1|1].l+1);
        tree[root].mark = 0;
    }
}
inline void Update(int l,int r,int ql,int qr,int root,long long x) {
    if (ql > r || qr < l) return;
    if (ql <= l && qr >= r) {
        tree[root].mark += x;
        tree[root].sum += x*(r-l+1);
        return;
    }
    pushdown(root);
    int mid = l+r>>1;
    Update(l,mid,ql,qr,root<<1,x);
    Update(mid+1,r,ql,qr,root<<1|1,x);
    tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum;
}
inline long long Query(int l,int r,int ql,int qr,int root) {
    if (ql > r || qr < l) return 0;
    if (ql <= l && qr >= r) return tree[root].sum;
    pushdown(root);
    int mid = l+r>>1;
    return Query(l,mid,ql,qr,root<<1)+Query(mid+1,r,ql,qr,root<<1|1);
}
inline long long QueryEdges(int u,int v) {
    int topu = top[u];
    int topv = top[v];
    long long sum = 0;
    while (topu != topv) {
        if (dep[topu] < dep[topv]) {
            swap(topu,topv);
            swap(u,v);
        }
        sum += Query(1,cnt,num[topu],num[u],1);
        u = father[topu];
        topu = top[u];
    }
    if (dep[u] > dep[v]) swap(u,v);
    return sum+Query(1,cnt,num[u],num[v],1);
}
int main() {
    scanf("%d%d",&n,&m);
    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);
        edges[u].push_back(v);
        edges[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,1);
    BuildTree(1,cnt,1);
    while (m--) {
        long long dispose,x,y;
        scanf("%lld%lld",&dispose,&x);
        if (dispose == 1) {
            scanf("%lld",&y);
            Update(1,cnt,num[x],num[x],1,y);
        } else if (dispose == 2) {
            scanf("%lld",&y);
            Update(1,cnt,num[x],num[x]+size[x]-1,1,y);
        } else if (dispose == 3) printf("%lld\n",QueryEdges(1,x));
    }
    return 0;
}