码迷,mamicode.com
首页 > 其他好文 > 详细

O - Snacks(DFS序)

时间:2019-07-31 11:04:48      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:amp   printf   names   ons   就是   输入数据   typedef   put   提交   

百度科技园内有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序)

标签:amp   printf   names   ons   就是   输入数据   typedef   put   提交   

原文地址:https://www.cnblogs.com/cherish-lin/p/11274509.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!