bzoj4034 [HAOI2015]树上操作

4034: [HAOI2015]树上操作

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 6323  Solved: 2094
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

 

Sample Input

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

Sample Output

6
9
13

HINT

 

 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

 

Source

鸣谢bhiaibogf提供

分析:这题很显然要用到树链剖分+线段树吧,因为要维护路径.那么对于子树的操作,记录一下dfs序就可以了.
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const long long maxn = 200010;

long long n,m,head[maxn],nextt[maxn],to[maxn],tot = 1,a[maxn],L[maxn << 2],R[maxn << 2],pos[maxn],ppos[maxn],fa[maxn];
long long sizee[maxn],deep[maxn],top[maxn],son[maxn],cnt,endd[maxn];
long long sum[maxn << 2],tag[maxn << 2];

void add(long long x,long long y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void dfs(long long u,long long faa,long long dep)
{
    sizee[u] = 1;
    deep[u] = dep;
    for (long long i = head[u];i;i = nextt[i])
    {
        long long v = to[i];
        if (v == faa)
            continue;
        fa[v] = u;
        dfs(v,u,dep + 1);
        sizee[u] += sizee[v];
        if (sizee[v] > sizee[son[u]])
            son[u] = v;
    }
}

void dfs2(long long u,long long topp)
{
    top[u] = topp;
    pos[u] = ++cnt;
    ppos[cnt] = u;
    if (son[u])
        dfs2(son[u],topp);
    for (long long i = head[u];i;i = nextt[i])
    {
        long long v = to[i];
        if (v == fa[u] || v == son[u])
            continue;
        dfs2(v,v);
    }
    endd[u] = cnt;
}

void pushdown(long long o)
{
    if (tag[o])
    {
        tag[o * 2] += tag[o];
        tag[o * 2 + 1] += tag[o];
        sum[o * 2] += tag[o] * (R[o * 2] - L[o * 2] + 1);
        sum[o * 2 + 1] += tag[o] * (R[o * 2 + 1] - L[o * 2 + 1] + 1);
        tag[o] = 0;
    }
}

void pushup(long long o)
{
    sum[o] = sum[o * 2] + sum[o * 2 + 1];
}

void build(long long o,long long l,long long r)
{
    L[o] = l;
    R[o] = r;
    if (l == r)
    {
        sum[o] = a[ppos[l]];
        return;
    }
    long long mid = (l + r) >> 1;
    build(o * 2,l,mid);
    build(o * 2 + 1,mid + 1,r);
    pushup(o);
}

void update(long long o,long long l,long long r,long long x,long long y,long long v)
{
    if (x <= l && r <= y)
    {
        tag[o] += v;
        sum[o] += v * (r - l + 1);
        return;
    }
    pushdown(o);
    long long mid = (l + r) >> 1;
    if (x <= mid)
        update(o * 2,l,mid,x,y,v);
    if (y > mid)
        update(o * 2 + 1,mid + 1,r,x,y,v);
    pushup(o);
}

long long query(long long o,long long l,long long r,long long x,long long y)
{
    if (x <= l && r <= y)
        return sum[o];
    pushdown(o);
    long long mid = (l + r) >> 1,res = 0;
    if (x <= mid)
        res += query(o * 2,l,mid,x,y);
    if (y > mid)
        res += query(o * 2 + 1,mid + 1,r,x,y);
    return res;
}

long long queryy(long long x)
{
    long long res = 0;
    while (top[x] != 1)
    {
        res += query(1,1,n,pos[top[x]],pos[x]);
        x = fa[top[x]];
    }
    res += query(1,1,n,pos[1],pos[x]);
    return res;
}

int main()
{
    scanf("%lld%lld",&n,&m);
    for (long long i = 1; i <= n; i++)
        scanf("%lld",&a[i]);
    for (long long i = 1; i < n; i++)
    {
        long long x,y;
        scanf("%lld%lld",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    for (long long i = 1; i <= m; i++)
    {
        long long id,x,y;
        scanf("%lld",&id);
        if (id == 1)
        {
            scanf("%lld%lld",&x,&y);
            update(1,1,n,pos[x],pos[x],y);
        }
        if (id == 2)
        {
            scanf("%lld%lld",&x,&y);
            update(1,1,n,pos[x],endd[x],y);
        }
        if (id == 3)
        {
            scanf("%lld",&x);
            printf("%lld\n",queryy(x));
        }
    }

    return 0;
}

 

posted @ 2018-01-19 12:49  zbtrs  阅读(150)  评论(0编辑  收藏  举报