SDUT 4778 - Cut the tree (树上启发式合并)

题目链接

题面:

Cut the tree

Description

给一个具有 N 个节点的有根树,以 1 号节点为根,节点编号从 1 开始,点有点权。

树的第 H 层权值为深度为 H 的所有点的点权之和。

树的总权值为所有层权值的最大值。

问分别割掉以 1,2,…,N 为根的子树后,剩余树的总权值为多少。

Input
第一行输入一个正整数 N 表示节点的个数。(2 <= N <= 100000)

接下来 N-1 行每行两个正整数 x , y,表示节点 x 和节点 y 之间有边。

最后一行输入N个正整数,v1,v2,…,vn 分别表示每个节点的点权。(1 <= vi <= 1000000000)

Output
输出 N 个整数,分别表示割掉以 1,2,…,N 为根的子树后,剩余树的总权值。

Sample
Input
6

2 4

3 4

4 1

5 1

6 5

3 7 6 1 4 5

Output
0 11 12 5 13 13

题解:
树上启发式合并,同时用线段树维护最大值。
这个解法是两个log的,只能过简单版本,难度较大的版本过不去。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<set>
#define ll long long
#define pr make_pair
#define pb push_back
#define ui unsigned int
#define lc (cnt<<1)
#define rc (cnt<<1|1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007;
const double eps=1e-8;
const double dnf=1e20;
const double pi=acos(-1.0);
const int maxn=100100;
const int up=100;
const int maxp=1100;
struct node
{
    int l,r;
    ll maxx;
}t[maxn<<2];

int c[maxn];
ll cval[maxn];

void pushup(int cnt)
{
    t[cnt].maxx=max(t[lc].maxx,t[rc].maxx);
}

void build(int l,int r,int cnt)
{
    t[cnt].l=l,t[cnt].r=r;
    t[cnt].maxx=0;
    if(l==r)
    {
        t[cnt].maxx=cval[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,lc);
    build(mid+1,r,rc);
    pushup(cnt);
}

void change(int pos,int cnt,int val)
{
    if(t[cnt].l==t[cnt].r)
    {
        t[cnt].maxx+=val;
        return ;
    }
    if(pos<=t[lc].r) change(pos,lc,val);
    else change(pos,rc,val);
    pushup(cnt);
}

int head[maxn],ver[maxn<<1],nt[maxn<<1],tot=1;
int si[maxn],son[maxn],n;
int q[maxn],maxx;
ll val[maxn];

void add(int x,int y)
{
    ver[++tot]=y,nt[tot]=head[x],head[x]=tot;
}

void bfs(int s)
{
    int l=1,r=1;
    maxx=1;
    q[1]=s;
    c[s]=1;
    cval[c[s]]+=val[s];
    while(l<=r)
    {
        int x=q[l++];
        for(int i=head[x];i;i=nt[i])
        {
            int y=ver[i];
            if(c[y]) continue;
            c[y]=c[x]+1;
            maxx=max(maxx,c[y]);
            cval[c[y]]+=val[y];
            q[++r]=y;
        }
    }
}

void dfs1(int x,int fa)
{
    int maxson=0;
    si[x]=1;
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa) continue;
        dfs1(y,x);
        si[x]+=si[y];
        if(si[y]>maxson) maxson=si[y],son[x]=y;
    }
}

ll ans[maxn];
int hson=0;

void in(int x,int fa,int f)
{
    change(c[x],1,val[x]*f);
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa||y==hson) continue;
        in(y,x,f);
    }
}

void dfs2(int x,int fa,int flag)
{
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(y==fa||y==son[x]) continue;
        dfs2(y,x,0);
    }
    if(son[x])
    {
        dfs2(son[x],x,1);
        hson=son[x];
    }
    in(x,fa,-1);
    ans[x]=t[1].maxx;
    hson=0;
    if(!flag) in(x,fa,1);
}


int main(void)
{
    scanf("%d",&n);
    int x,y;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++)
        scanf("%lld",&val[i]);
    bfs(1);
    build(1,maxx,1);
    dfs1(1,0);
    dfs2(1,0,0);
    for(int i=1;i<=n;i++)
    {
        if(i!=1)putchar(' ');
        printf("%lld",ans[i]);
    }
    putchar('\n');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值