• CodeForces


    思路:
    考虑选了一个点u就加上他的权值w[u] ,那么对于与u距离小于K的点v,作w[v]-w[u] ,相当于对v造成选u不选v的影响。如果有的点点权变成了负数,那么这个点一定不会被选。如果有的点点权还是正数且之前被w[u]更新了,那就再加上这个点的权值进行“补差”,就相当于选了这个点而没有选u,而如果没有w[u]被更新,则相当于选了 u、v 两个点

    然后就是选点顺序的问题,一种可行的方案就是从叶子节点开始,因为叶子节点没有儿子了,而叶子结点对内能影响到的点,父亲也能影响到,从外面一层一层向内收,外面的肯定是处理完了的(子树w[] 为非正),那么对于当前点来说就等同于“叶子”了,所以避免了后效性。

    如果从根开始选的的话,比如A 是根,设w[C]<w[A]<w[B],A能影响B、C, 之后dfs找到C,发现w[C]<0 (被w[A] 更新过),则不会选,因为C原来的权值肯定小于A,之后找到B ,w[B]>0,所以会加上 w[B],这是就相当于取了点B,而如果B和C距离大于K了,那么对于一开始选了B来说,C是可选的,而C却在之前已经抛弃了,并且被更新成了负,则会出现后效性;

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pLL;
    const int N=2e2+5;
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch=getchar();
        while(!isdigit(ch)){ if(ch=='-')t=-1; ch=getchar(); }
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    struct edge
    {
        int from,to,next;
        edge(){}
        edge(int ff,int tt,int nn)
        {
            from=ff; to=tt; next=nn;
        }
    };
    
    edge e[N<<1];
    vector<int> a[N];
    int f[N],head[N],w[N],tot,n,k;
    void add(int from,int to)
    {
        e[++tot]=edge(from,to,head[from]);
        head[from]=tot;
    }
    void dfs(int u,int pre,int deep)
    {
        a[deep].pb(u);
        for(int i=head[u];i;i=e[i].next)
            if(e[i].to!=pre) dfs(e[i].to,u,deep+1);
    }
    void dfs2(int u,int pre,int step,int val)
    {
        w[u]-=val;
        if(step==k) return;
        for(int i=head[u];i;i=e[i].next)
            if(e[i].to!=pre) dfs2(e[i].to,u,step+1,val);
    }
    int main()
    {
        n=read(),k=read();
        for(int i=1;i<=n;i++) w[i]=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y); add(y,x);
        }
        dfs(1,0,1);
        int ans=0;
        for(int i=n;i;i--)
        {
            for(int j=0;j<a[i].size();j++)
            {
                //printf("u=%d deep=%d
    ",a[i][j],i);
                int u=a[i][j];
                if(w[u]<=0) continue;
                ans+=w[u];
                dfs2(u,0,0,w[u]);
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    如何通過編程獲取列表項目的附件以及多行文本中的文件內容
    小技巧:如何管理保存在本地的用户凭据
    WF 4.0中如何实现xaml工作流的动态加载
    使用jquery构造自己的多级菜单
    和安蕾尔的合影
    360太tmd脑残了
    3D 打印机技术设想
    再放2张数字油画
    解决问题的艺术:半小时编程实现照片的反转负冲特效
    承接数字油画图稿/线条图定制(出图)业务
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12025178.html
Copyright © 2020-2023  润新知