[bzoj3252]攻略【dfs序】【线段树】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=3252
【题解】
  一个显而易见的贪心:每次一定取价值和最大的路径。
  所以我们可以把每个点的权值设为它的到根的路径的价值和,然后按dfs序排好序后存入线段树种中。修改时,从叶节点开始往上走,每次把子树的所有点的权值减去它的价值(dfs中的一段区间)。直到遇到一个已经被修改过的点。
  时间复杂度:O(NlogN)

/* --------------
    user Vanisher
    problem bzoj-3252 
----------------*/
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       200010
using namespace std;
ll read(){
    ll tmp=0, fh=1; char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    return tmp*fh;
}
struct Edge{
    ll data,next;
}e[N*2];
struct Tree{
    ll pl,pr,mx,tag,mxi,l,r;
}T[N*3];
ll num[N],sum[N],p[N],dad[N],head[N],place,id,l[N],r[N],now[N],n,k;
void build(ll u, ll v){
    e[++place].data=v; e[place].next=head[u]; head[u]=place;
}
void dfs(ll x, ll fa){
    p[x]=++id; l[p[x]]=id; dad[p[x]]=p[fa]; 
    now[p[x]]=num[x];
    sum[p[x]]=now[p[x]]+sum[p[fa]];
    for (ll ed=head[x]; ed!=0; ed=e[ed].next)
        if (e[ed].data!=fa) dfs(e[ed].data,x);
    r[p[x]]=id;
}
void pushtag(ll x){
    if (T[x].tag!=0){
        if (T[x].l!=T[x].r){
            T[T[x].pl].mx+=T[x].tag, T[T[x].pr].mx+=T[x].tag;
            T[T[x].pl].tag+=T[x].tag, T[T[x].pr].tag+=T[x].tag;
        }
        T[x].tag=0;
    }
}
void reget(ll x){
    T[x].mx=max(T[T[x].pl].mx,T[T[x].pr].mx);
    if (T[T[x].pl].mx==T[x].mx)
        T[x].mxi=T[T[x].pl].mxi;
        else T[x].mxi=T[T[x].pr].mxi;
}
ll create(ll l, ll r){
    ll p=++place;
    T[p].l=l, T[p].r=r;
    if (l==r) T[p].mx=sum[l], T[p].mxi=l;
        else {
            ll mid=(l+r)/2;
            T[p].pl=create(l,mid);
            T[p].pr=create(mid+1,r);
            reget(p);
        }
    return p;
}
void modify(ll p, ll l, ll r, ll data){
    pushtag(p);
    if (T[p].l==l&&T[p].r==r){
        T[p].tag+=data; T[p].mx+=data;
        return;
    }
    ll mid=(T[p].l+T[p].r)/2;
    if (mid>=r) modify(T[p].pl,l,r,data);
        else if (mid<l) modify(T[p].pr,l,r,data);
            else modify(T[p].pl,l,mid,data), modify(T[p].pr,mid+1,r,data);
    reget(p);
}
int main(){
    n=read(), k=read();
    for (ll i=1; i<=n; i++)
        num[i]=read();
    for (ll i=1; i<n; i++){
        ll u=read(), v=read();
        build(u,v); build(v,u);
    }
    place=0; dfs(1,0);
    ll rt=create(1,n),ans=0;
    for (ll i=1; i<=k; i++){
        ll tmp=T[rt].mxi;
        ans=ans+T[rt].mx;
        while (now[tmp]!=0){
            modify(rt,l[tmp],r[tmp],-now[tmp]);
            now[tmp]=0;
            tmp=dad[tmp];
        }
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-04-20 22:22  Vanisher  阅读(130)  评论(0编辑  收藏  举报