bzoj 4034(DFS序+线段树)

这个题多了一个操作难度直线上升,看完题解才会写

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

按照题意:记录其DFS序,然后进栈是正,出栈为负,利用线段树进行更新

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
const int N = 800005;
struct Edge
{
    int v,next;
} edge[N<<1];
int head[N],tot,cnt;
int val[N];
int in[N],out[N];
LL tree[N<<2],lazy[N<<2],seg[N];
int flag[N<<2];
int io[N];
void addEdge(int u,int v)
{
    edge[tot].v = v,edge[tot].next = head[u],head[u] = tot++;
}
void init()
{
    memset(head,-1,sizeof(head));
    memset(val,0,sizeof(val));
    memset(lazy,0,sizeof(lazy));
    memset(io,0,sizeof(io));
    memset(seg,0,sizeof(seg));
    tot = cnt = 0;
}
void dfs(int u,int fa)
{
    seg[in[u] = ++cnt] = (LL)val[u];
    io[cnt] = 1;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        if(edge[i].v != fa)
        {
            dfs(edge[i].v,u);
        }
    }
    seg[out[u] = ++cnt] = (LL)(-val[u]);
    io[cnt] = -1;
}

void pushup(int idx)
{
    tree[idx] = tree[idx<<1]+tree[idx<<1|1];
    return;
}
void pushdown(int idx)
{
    if(lazy[idx])
    {
        tree[idx << 1] +=  flag[idx<<1]*lazy[idx];
        tree[idx << 1 | 1] += flag[idx<<1|1]*lazy[idx];
        lazy[idx << 1] += lazy[idx];
        lazy[idx << 1 | 1] += lazy[idx];
        lazy[idx] = 0;
    }
    return;
}
void build(int l,int r,int idx)
{
    if(l==r)
    {
        tree[idx] = seg[l];
        if(io[l]>0) flag[idx] = 1;
        else flag[idx] = -1;
        return;
    }
    int mid = (l+r)>>1;
    build(l,mid,idx<<1);
    build(mid+1,r,idx<<1|1);
    pushup(idx);
    flag[idx] = flag[idx<<1] + flag[idx<<1|1];
}
void update(int l,int r,int L,int R,int idx,int val)
{
    if(l>=L&&r<=R)
    {
        tree[idx] =tree[idx] + (LL)flag[idx]*val;
        lazy[idx] =lazy[idx] + (LL)val;
        return;
    }
    int mid = (l+r)>>1;
    pushdown(idx);
    if(mid>=L) update(l,mid,L,R,idx<<1,val);
    if(mid<R) update(mid+1,r,L,R,idx<<1|1,val);
    pushup(idx);
}
LL query(int l,int r,int L,int R,int idx){
    if(l>=L&&r<=R)
    {
        return tree[idx];
    }
    int mid = (l+r)>>1;
    LL sum = 0;
    pushdown(idx);
    if(mid>=L) sum+=query(l,mid,L,R,idx<<1);
    if(mid<R) sum+=query(mid+1,r,L,R,idx<<1|1);
    return sum;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&val[i]);
        }
        for(int i=1; i<n; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addEdge(u,v);
            addEdge(v,u);
        }
        dfs(1,0);
        build(1,2*n,1);
        while(m--)
        {
            int op,x,y;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d%d",&x,&y);
                update(1,2*n,in[x],in[x],1,y);
                update(1,2*n,out[x],out[x],1,y);
            }else if(op==2){
                scanf("%d%d",&x,&y);
                update(1,2*n,in[x],out[x],1,y);
            }else{
                scanf("%d",&x);
                LL sum = query(1,2*n,1,in[x],1);
                printf("%lld\n",sum);
            }
        }
    }
}

 

posted @ 2016-10-16 09:46  樱花庄的龙之介大人  阅读(942)  评论(0编辑  收藏  举报