hdu 5692 dfs序 线段树

题目概括

给定一棵n个点的有根树,每个点有一个点权。根节点为0,节点标号为0~n-1。

定义最大路径为:从根出发走到某个点,点权和最大的路径。

现在有Q次操作,每种是以下两种之一:

(1).将点x的点权变成v。

(2).求经过某一个点的最大路径的点权和

参考博客 http://www.cnblogs.com/zhouzhendong/p/7263838.html

思路:

w[x]为节点x的权值     Dis[x]为从根节点到达当前节点的权值

那么,一开始,dis[x]可以通过一遍dfs全部求出来。

如何处理更改和询问呢?那么我们从询问入手

题目询问的是经过一个点的最大路径的点权和,那么其实就是到达这个节点或者其子孙节点的最大dis[x], 其实就是查询整个子树的max(dis[x])

  在树的dfs序中,同一个子树节点的所对应的序号一定是整个dfs序中的连续的一段!

那么我们就可以把询问转化成“求区间最大值”的问题了。然而同理思考,那么修改其实就是修改整个子树的最大值!对于0 x y, 其实就是子树x的所有节点都增加y-w[x]!那么最大值也增加y-w[x]。

问题就变成了一个询问区间最大值和区间修改(同增或者同减)的问题了。

 

 

#include<bits/stdc++.h>
using namespace std;

#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

const int N = 1E5+3;
const int M = 1E5+3;
const ll LINF = 1e17+3;


int n,m;
ll tmax[N<<2],col[N<<2];
int vis[N], tim,in[N],out[N];
ll v[N],d[N];
vector<int>V[N];
//距离d[N]需要注意   因为这里的1..n不是表示点1..n 而是dfs序的1..n
void dfs(int pre,int t){
    int len = V[t].size();
    in[t]=++tim;
    d[in[t]]  = d[in[pre]]+v[t];
    for(int i=0;i<len;++i){
        if(vis[V[t][i]])continue;
        vis[V[t][i]]=1;
        dfs(t,V[t][i]);
    }
    out[t]=tim;
}


void pushup(int rt){
    tmax[rt] = max(tmax[rt<<1],tmax[rt<<1|1]);
}
void pushdown(int rt,int len){
    if(col[rt]){
        col[rt<<1] +=col[rt];
        col[rt<<1|1]+=col[rt];
        tmax[rt<<1]+=col[rt];
        tmax[rt<<1|1]+=col[rt];
        col[rt]=0;
    }
}

void build(int l,int r,int rt){
    col[rt] = 0;
    if(l==r){
        tmax[rt] = d[l]; return ;
    }
    int mid = (l+r)/2;
    build(lson);build(rson);
    pushup(rt);
}
void update(int l,int r,int rt,int a,int b ,ll val){
    if(a<=l && b>=r){
        col[rt]+=val;
        tmax[rt]+=val;
        return ;
    }
    pushdown(rt,r-l+1);
    int mid =(l+r)/2;
    if(a<=mid)update(lson,a,b,val);
    if(b>mid)update(rson,a,b,val);
    pushup(rt);
}
ll query(int l,int r,int rt,int a,int b){
    if(a<=l && b>=r){
        return tmax[rt];
    }
    int mid =(l+r)/2;
    pushdown(rt,r-l+1);
    ll ans= -LINF;
    if(a<=mid)
        ans = max(ans, query(lson,a,b));
    if(b>mid)
        ans = max(ans,query(rson,a,b));
    return ans;
}

int main(){

    int t;

    cin>>t;
    int cnt=1;

        while(t--){
            tim= 0 ;
            memset(vis,0,sizeof(vis));
            memset(col,0,sizeof(col));
            scanf("%d %d",&n,&m);
            for(int i=0;i<=n;++i)V[i].clear();

            for(int i=1;i<n;++i){
                int u,v;
                scanf("%d %d",&u,&v);
                u++;v++;
                V[u].pb(v);
                V[v].pb(u);
            }
            for(int i=1;i<=n;++i){
                scanf("%lld",&v[i]); d[i]=v[i];
            }

            vis[1]=1;
            d[0]=0;
            dfs(0,1);
            build(1,n,1);

            printf("Case #%d:\n",cnt++);
            while(m--){
                int c,x;ll y;
                scanf("%d",&c);
                if(c==0){
                    //修改  成Y   也就是将x以及所有子树修改成Y  也就是增加 y-v[x] , v[x]=y;
                    scanf("%d %lld",&x,&y);x++;
                    update(1,n,1,in[x],out[x],y-v[x]);
                    v[x]=y;
                }
                else {
                    //询问到x
                    scanf("%d",&x);x++;
                    printf("%lld\n",query(1,n,1,in[x],out[x]));
                }
            }
        }
    return 0;
}

 

posted on 2018-10-21 22:06  Helpp  阅读(145)  评论(0编辑  收藏  举报

导航