dfs+线段树______Snakes(hdu 5692 2016百度之星初赛A)

Problem Description

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

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

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

Input

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

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

接下来n-1n1行,每行两个整数xxy(0\leq x,y < n)y(0x,y<n),表示编号为xx的零食机与编号为yy的零食机相连。

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

接下来mm行,有两种操作:0\ x\ y0 x y,表示编号为xx的零食机的价值变为yy1\ 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


分析:很显然这个一个树,视作0为根节点。从0号节点到某一节点有且只有一条可达路径。那么每个节点i可以对应一个路径(从0到i这条路径)。对路径通过后序遍历重新编号为1~n.叶子节点所对应区间为[Ki,Kii].Ki为该节点对应的路径的编号。对于非叶子节点对应区间为[Min,Max],Min是该节点所有孩子节点区间左端点中最小的。Max肯定为自身(因为父节点的路径编号要大于孩子节点的路径编号)。那么这个区间的意义是? 如果一个节点C的区间为[1,3]那么1,2,3这三个编号对应的路径中都经过节点C。并且可以算出每个路径的值也就是说节点0到每个节点的路径长度.NUM[I] 0~i路径的长度。

那么查询操作求经过X节点的最大路径就是X对应的区间[ L[X],R[X] ]中的这些路径对应NUM值的最大值。注意:这里是找一个区间的最大值。

而修改操作让X节点的值改为Y,也就是将X对应区间[ L[X],R[X] ]中这些路径对应的每个NUM值都加上Y-V[X]。(V[X]为原本X节点的价值)。 注意:这里是修改一个区间的值。

所以我们可以看出来,我们可以先用dfs处理,然后用线段树去优化后面的操作。


代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int MAXN = 100100;
vector<int> edge[MAXN];
int m,n;

struct treenode
{
    int left,right,mid;
    ll maxx,add;
}tree[MAXN<<4];

int L[MAXN],R[MAXN],index;
int w[MAXN];
ll num[MAXN];
void built(int l,int r,int rt)
{
    tree[rt].left = l;
    tree[rt].right = r;
    tree[rt].mid = (l+r)>>1;
    tree[rt].add = 0;
    if(l == r)
    {
        tree[rt].maxx = num[l];
        return;
    }
    built(l,tree[rt].mid,rt<<1);
    built(tree[rt].mid+1,r,(rt<<1)|1);
    tree[rt].maxx = max(tree[rt<<1].maxx,tree[(rt<<1)|1].maxx);
}

void update(int rt,int l,int r,int data)
{
    if(tree[rt].left == l && r == tree[rt].right)
    {
        tree[rt].add += data;
        return;
    }
    if(tree[rt].add != 0)
    {
        tree[rt<<1].add += tree[rt].add;
        tree[(rt<<1)|1].add += tree[rt].add;
        tree[rt].add = 0;
    }
    if(r <= tree[rt].mid)
    {
        update(rt<<1,l,r,data);
    }
    else if( l > tree[rt].mid)
    {
        update((rt<<1)|1,l,r,data);
    }
    else
    {
        update(rt<<1,l,tree[rt].mid,data);
        update((rt<<1)|1,tree[rt].mid+1,r,data);
    }
    tree[rt].maxx = max(tree[rt<<1].maxx + tree[rt<<1].add,tree[(rt<<1)|1].maxx + tree[(rt<<1)|1].add);
}

ll query(int rt,int l,int r)
{
    if(tree[rt].left == l && r == tree[rt].right )
    {
        return tree[rt].maxx + tree[rt].add;
    }
    if(tree[rt].add != 0)
    {
        tree[rt<<1].add += tree[rt].add;
        tree[(rt<<1)|1].add += tree[rt].add;
        tree[rt].add = 0;
    }
    ll ans;
    if(r <= tree[rt].mid)
    {
        ans = query(rt<<1,l,r);
    }
    else if( l > tree[rt].mid)
    {
        ans = query((rt<<1)|1,l,r);
    }
    else
    {
       ans = max(query(rt<<1,l,tree[rt].mid),query((rt<<1)|1,tree[rt].mid+1,r));
    }
    tree[rt].maxx = max(tree[rt<<1].maxx + tree[rt<<1].add,tree[(rt<<1)|1].maxx + tree[(rt<<1)|1].add);
    return ans;
}

void dfs(int now,int pre,ll sum)
{
    sum += w[now];
    int son = 0;
    L[now] = MAXN;
    for(int i = 0 ; i < edge[now].size() ; i ++)
    {
        int next = edge[now][i];
        if(next == pre) continue;
        son ++;
        dfs(next,now,sum);
        L[now] = min(L[now],L[next]);
    }
    R[now] = ++index;
    num[index] = sum;
    if(son == 0)
    {
        L[now] = R[now];
    }
}
int main()
{
    int t,Case = 0;
    cin >> t;
    while(t--)
    {
        printf("Case #%d:\n",++Case);
        cin >> n >> m;
        int u,v;
        for(int i = 0 ; i <= n ; i ++) edge[i].clear();
        for(int i = 0 ; i < n - 1 ; i ++)
        {
            cin >> u >> v;
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        for(int i = 0 ; i < n ; i ++)
            scanf("%d",&w[i]);
        index = 0;
        dfs(0,0,0);
        built(1,n,1);
        int op;
        for(int i = 0 ; i < m ; i ++)
        {
            scanf("%d",&op);
            if(op == 0)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                int data = y - w[x];
                w[x] = y;
                update(1,L[x],R[x],data);
            }
            else
            {
                int x;
                scanf("%d",&x);
                printf("%lld\n",query(1,L[x],R[x]));
            }
        }
    }
    return 0;
}


上面代码的线段树写略丑。应该是更新的姿势不太对。

下面这个线段树时间要比上面的快很多

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int MAXN = 100100;
vector<int> edge[MAXN];
int m,n;

struct treenode
{
    int left,right,mid;
    ll maxx,add;
}tree[MAXN<<4];

int L[MAXN],R[MAXN],index;
ll w[MAXN],num[MAXN];

void built(int l,int r,int rt)
{
    tree[rt].left = l;
    tree[rt].right = r;
    tree[rt].mid = (l+r)>>1;
    tree[rt].add = 0;
    if(l == r)
    {
        tree[rt].maxx = num[l];
        return;
    }
    built(l,tree[rt].mid,rt<<1);
    built(tree[rt].mid+1,r,(rt<<1)|1);
    tree[rt].maxx = max(tree[rt<<1].maxx,tree[(rt<<1)|1].maxx);
}

void update(int rt,int l,int r,ll data)
{
    if(tree[rt].add != 0)
    {
        if(tree[rt].left != tree[rt].right)
        {
            tree[rt<<1].maxx += tree[rt].add;
            tree[rt<<1].add += tree[rt].add;
            tree[(rt<<1)|1].maxx += tree[rt].add;
            tree[(rt<<1)|1].add += tree[rt].add;
            tree[rt].add = 0;
        }
    }
    if(tree[rt].left == l && r == tree[rt].right)
    {
        tree[rt].maxx += data;
        tree[rt].add += data;
        return;
    }

    if(r <= tree[rt].mid)
    {
        update(rt<<1,l,r,data);
    }
    else if( l > tree[rt].mid)
    {
        update((rt<<1)|1,l,r,data);
    }
    else
    {
        update(rt<<1,l,tree[rt].mid,data);
        update((rt<<1)|1,tree[rt].mid+1,r,data);
    }
    tree[rt].maxx = max(tree[rt<<1].maxx,tree[(rt<<1)|1].maxx);
}

ll query(int rt,int l,int r)
{
    if(tree[rt].add != 0)
    {
        if(tree[rt].left != tree[rt].right)
        {
            tree[rt<<1].maxx += tree[rt].add;
            tree[rt<<1].add += tree[rt].add;
            tree[(rt<<1)|1].maxx += tree[rt].add;
            tree[(rt<<1)|1].add += tree[rt].add;
            tree[rt].add = 0;
        }
    }
    if(tree[rt].left == l && r == tree[rt].right )
    {
        return tree[rt].maxx;
    }
    if(r <= tree[rt].mid)
    {
        return query(rt<<1,l,r);
    }
    else if( l > tree[rt].mid)
    {
        return query((rt<<1)|1,l,r);
    }
    else
    {
       return max(query(rt<<1,l,tree[rt].mid),query((rt<<1)|1,tree[rt].mid+1,r));
    }
}

void dfs(int now,int pre,ll sum)
{
    sum += w[now];
    int son = 0;
    L[now] = MAXN;
    for(int i = 0 ; i < edge[now].size() ; i ++)
    {
        int next = edge[now][i];
        if(next == pre) continue;
        son ++;
        dfs(next,now,sum);
        L[now] = min(L[now],L[next]);
    }
    R[now] = ++index;
    num[index] = sum;
    if(son == 0)
    {
        L[now] = R[now];
    }
}
int main()
{
    int t,Case = 0;
    cin >> t;
    while(t--)
    {
        printf("Case #%d:\n",++Case);
        scanf("%d%d",&n,&m);
        int u,v;
        for(int i = 0 ; i <= n ; i ++) edge[i].clear();
        for(int i = 0 ; i < n - 1 ; i ++)
        {
            scanf("%d%d",&u,&v);
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        for(int i = 0 ; i < n ; i ++)
            scanf("%lld",&w[i]);
        index = 0;
        dfs(0,0,0);
        built(1,n,1);
        int op;
        for(int i = 0 ; i < m ; i ++)
        {
            scanf("%d",&op);
            if(op == 0)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                ll data = y - w[x];
                w[x] = y;
                update(1,L[x],R[x],data);
            }
            else
            {
                int x;
                scanf("%d",&x);
                printf("%lld\n",query(1,L[x],R[x]));
            }
        }
    }
    return 0;
}





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值