• [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
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    VS2005调试网站时不显示Flash元素
    js中使用弹出窗体
    Ipod Touch/Iphone歌词同步软件整理
    Chrome Dev 4.0.*增加flash支持
    字符串数组排序(qsort参数 比较函数)
    查找两个已经排好序的数组的第k大的元素
    求用1,2,5这三个数不同个数组合的和为100的组合个数
    Hadoop分布式环境下的数据抽样(转)
    Reservoir Sampling
    欧拉回路
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135950.html
Copyright © 2020-2023  润新知