O - Snacks(DFS序)

Posted cherish-lin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了O - Snacks(DFS序)相关的知识,希望对你有一定的参考价值。

百度科技园内有nn个零食机,零食机之间通过n1n−1条路相互连通。每个零食机都有一个值vv,表示为小度熊提供零食的价值。 

由于零食被频繁的消耗和补充,零食机的价值vv会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。 

为小度熊规划一个路线,使得路线上的价值总和最大。 

Input输入数据第一行是一个整数T(T10)T(T≤10),表示有TT组测试数据。 

对于每组数据,包含两个整数n,m(1n,m100000)n,m(1≤n,m≤100000),表示有nn个零食机,mm次操作。 

接下来n1n−1行,每行两个整数xx和y(0x,y<n)y(0≤x,y<n),表示编号为xx的零食机与编号为yy的零食机相连。 

接下来一行由nn个数组成,表示从编号为0到编号为n1n−1的零食机的初始价值v(|v|<100000)v(|v|<100000)。 

接下来mm行,有两种操作:0 x y0 x y,表示编号为xx的零食机的价值变为yy;1 x1 x,表示询问从编号为0的零食机出发,必须经过编号为xx零食机的路线中,价值总和的最大值。 

本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上: 

`#pragma comment(linker, "/STACK:1024000000,1024000000") `
Output对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。 

对于每次询问,输出从编号为0的零食机出发,必须经过编号为xx零食机的路线中,价值总和的最大值。 
Sample Input

1
6 5
0 1
1 2
0 3
3 4
5 3
7 -5 100 20 -5 -7
1 1
1 3
0 2 -1
1 1
1 5

Sample Output

Case #1:
102
27
2
20
题解:大体思路就是首先DFS标记每个点的时间戳,并且记录到每个点的路径(同时开一个Rev数组,从时间戳返回到原节点,建线段树的时候要用到).
知道了每个节点的时间戳,就知道了该节点的子树的区间,为[Start[x],End[x]],更新的话用线段树区间更新,查询的话用线段树区间查询,用到lazy数组.
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
const ll INF=0x3f3f3f3f3f3f3f3f;//这里一定是long long 啊啊啊啊
ll head[maxn],dis[maxn],w[maxn],Rev[maxn];
int Start[maxn],End[maxn];
int tot,cnt,n,m;
ll sum[maxn<<2],lazy[maxn<<2];
struct node

    ll v,next;
e[maxn<<1];
void add(int u,int v)

    e[tot]=(node)v,head[u];
    head[u]=tot++;

void DFS(int u,int pre)

    Start[u]=++cnt;
    Rev[cnt]=u;
    for(int i=head[u];i!=-1;i=e[i].next)
        int v=e[i].v;
        if(v==pre)continue;
        dis[v]=dis[u]+w[v];
        DFS(v,u);
    
    End[u]=cnt;

void pushup(int rt)

    sum[rt]=max(sum[rt*2],sum[rt*2+1]);

void pushdown(int rt)

    if(lazy[rt])
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        sum[rt<<1]+=lazy[rt];
        sum[rt<<1|1]+=lazy[rt];
        lazy[rt]=0;
    

void build(int l,int r,int rt)

    lazy[rt]=0;
    if(l==r)
        sum[rt]=dis[Rev[l]];
        return ;
    
    int mid=(l+r)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
    pushup(rt);

void update(int L,int R,int w,int l,int r,int rt)//[L,R]区间加上w

    if(L<=l&&R>=r)
        sum[rt]+=w;
        lazy[rt]+=w;
        return ;
    
    pushdown(rt);
    int mid=(l+r)>>1;
    if(L<=mid)update(L,R,w,l,mid,rt<<1);
    if(R>=mid+1)update(L,R,w,mid+1,r,rt<<1|1);
    pushup(rt);

ll querymax(int L,int R,int l,int r,int rt)

    if(L<=l&&R>=r)
        return sum[rt];
    
    pushdown(rt);
    ll ans=-INF;
    int mid=(l+r)>>1;
    if(L<=mid)ans=max(ans,querymax(L,R,l,mid,rt<<1));
    if(R>=mid+1)ans=max(ans,querymax(L,R,mid+1,r,rt<<1|1));
    return ans;

int main()

    int T,k=1;
    scanf("%d",&T);
    while(T--)
        cnt=tot=0;
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof(head));

        for(int i=1;i<=n-1;i++)
            int u,v;
            scanf("%d%d",&u,&v);
            u++;
            v++;
            add(u,v);
            add(v,u);
        
        for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
        dis[1]=w[1];
        DFS(1,-1);
        build(1,n,1);
        printf("Case #%d:\n", k++);
        while(m--)
            int op,x,y;
            scanf("%d%d",&op,&x);
            x++;
            if(op==1)
                printf("%lld\n",querymax(Start[x],End[x],1,n,1));
            
            else
                scanf("%d",&y);
                update(Start[x],End[x],y-w[x],1,n,1);
                w[x]=y;
            
        
    
    return 0;

 

以上是关于O - Snacks(DFS序)的主要内容,如果未能解决你的问题,请参考以下文章

hdu5692 Snacks dfs序+线段树

HDU 5692 - Snacks - [DFS序+线段树]

HDU5692 Snacks DFS序 线段树

Snacks

2016-5-21 letwetell Round3 (百度之星初赛,dfs序)

#144. DFS 序 1