HDU-5692 Snacks(dfs序+线段树)

题意

一棵 n 个节点的树,每个点有点权。在线实现 m 个操作,操作分两种:改变某点的点权,询问以 1 为节点,必须经过节点 x 的路径中点权和的最大值。
1 n , m 100000

思路

树上维护的东西一般跟询问有关,这里就按照题意,维护从 1 出发到某个节点的点权和,而经过 x 的路径,说明路径的终点一定属于以 x 为根的子树。那么在 x 的子树中取最大值即可,由此想到 d f s 序,并通过线段树查询区间最大值。而改变某个点的点权,会导致它的子树的值整体同时增加或减少一个同样的值,说明线段树的修改是区间加值的。再维护某个点实时的点权,并把修改点权改成在原来点权的基础上加一个值即可。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define N 100003
typedef long long LL;
using namespace std;
LL now[N];
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v){to[++tot]=v,nxt[tot]=head[u];head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct node
{
    int L,R;
    LL maxer,tag;
    void tag_up(LL val)
    {
        tag+=val;
        maxer+=val;
    }
    node operator +(const node &_)const{return (node){L,_.R,max(maxer,_.maxer),0};}
};
struct SegmentTree
{
    node nd[N<<2];
    void build(int k,int L,int R)
    {
        if(L==R)
        {
            nd[k].L=nd[k].R=L;
            nd[k].maxer=0;
            nd[k].tag=0;
            return;
        }
        build(k<<1,L,L+R>>1);
        build(k<<1|1,(L+R>>1)+1,R);
        nd[k]=nd[k<<1]+nd[k<<1|1];
    }
    void push_down(int k)
    {
        if(!nd[k].tag)return;
        nd[k<<1].tag_up(nd[k].tag);
        nd[k<<1|1].tag_up(nd[k].tag);
        nd[k].tag=0;
    }
    void update(int k,int L,int R,LL val)
    {
        if(L<=nd[k].L&&nd[k].R<=R)
        {
            nd[k].tag_up(val);
            return;
        }
        push_down(k);
        int mid=nd[k].L+nd[k].R>>1;
        if(L<=mid)update(k<<1,L,R,val);
        if(mid<R)update(k<<1|1,L,R,val);
        nd[k]=nd[k<<1]+nd[k<<1|1];
    }
    LL query(int k,int L,int R)
    {
        if(L<=nd[k].L&&nd[k].R<=R)return nd[k].maxer;
        push_down(k);
        int mid=nd[k].L+nd[k].R>>1;
        if(R<=mid)return query(k<<1,L,R);
        else if(L>mid)return query(k<<1|1,L,R);
        else return max(query(k<<1,L,R),query(k<<1|1,L,R));
    }
};
struct Tree
{
    Linked_list<N,N<<1>G;
    SegmentTree ST;
    int L[N],R[N],n,ord;
    void reset(int _){G.clear();ST.build(1,1,n=_);ord=0;}
    void add(int u,int v){G.add(u,v);G.add(v,u);}
    void dfs(int u,int fa)
    {
        L[u]=++ord;
        EOR(i,G,u)
        {
            int v=G.to[i];
            if(v!=fa)dfs(v,u);
        }
        R[u]=ord;
        return;
    }
    void update(int k,LL val)
    {
        ST.update(1,L[k],R[k],val-now[k]);
        now[k]=val;
    }
    void addval(int k,LL val){ST.update(1,L[k],R[k],val);}
    LL query(int k){return ST.query(1,L[k],R[k]);}
}T;

int main()
{
    int Task,n,m;
    scanf("%d",&Task);
    FOR(Ti,1,Task)
    {
        scanf("%d%d",&n,&m);
        printf("Case #%d:\n",Ti);
        T.reset(n);
        FOR(i,1,n-1)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            T.add(u+1,v+1);
        }
        T.dfs(1,-1);
        FOR(i,1,n)
        {
            scanf("%lld",&now[i]);
            T.addval(i,now[i]);
        }
        while(m--)
        {
            int op,x;
            LL y;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&x);
                printf("%lld\n",T.query(x+1));
            }
            else if(op==0)
            {
                scanf("%d%lld",&x,&y);
                T.update(x+1,y);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/81268509