• 【LOJ】#2268. 「SDOI2017」苹果树


    题解

    显然权值都是正的,我们最深的那个点一定延伸到了某个叶子

    我们抛去这条链之外再选K个点即可

    如果直接对一棵树选K个点,满足这样的依赖关系,可以通过一个后序遍历的顺序做出来
    转移方法是
    (dp[i][j] = dp[i - 1][k] + (j - k) * v)
    或者
    (dp[i][j] = dp[i - siz[u]][j])
    代表这个点选或者不选

    我们把每个点拆成1和a[i] - 1两个点,然后做两次儿子遍历顺序恰好相反的dp

    我们枚举一个叶子的时候,在这个点右侧这两个后序遍历重合的地方只有这个叶子到根所有点,这也是我们要必选的点

    然后我们用两个遍历中这个点左侧的点集,枚举每个点集选几个,来更新答案即可

    代码

    #include <bits/stdc++.h>
    #define enter putchar('
    ')
    #define space putchar(' ')
    #define fi first
    #define se second
    #define MAXN 40005
    //#define ivorysi
    #define pii pair<int,int>
    #define pb push_back
    using namespace std;
    typedef long long int64;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
        	if(c == '-') f = -1;
        	c = getchar();
        }
        while(c >= '0' && c <= '9') {
        	res = res * 10 + c - '0';
        	c = getchar();
        }
        res *= f;
    }
    
    template<class T>
    void out(T x) {
        if(x < 0) {putchar('-');x = -x;}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    struct node {
        int to,next;
    }E[MAXN * 2];
    int64 tot;
    int N,K,head[MAXN],sumE,fa[MAXN],Ncnt,v[MAXN],a[MAXN],sumv[MAXN];
    int siz[MAXN],dep[MAXN],LA[MAXN],posA[MAXN],LB[MAXN],posB[MAXN],idx;
    int f[51000005],g[51000005],Q1[500005],Q2[500005],ql,qr;
    bool lef[MAXN];
    void add(int u,int v) {
        E[++sumE].to = v;
        E[sumE].next = head[u];
        head[u] = sumE;
    }
    void dfsa(int u) {
        siz[u] = 1;dep[u] = dep[fa[u]] + 1;sumv[u] = sumv[fa[u]] + v[u];
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;
            dfsa(v);siz[u] += siz[v];
        }
        LA[++idx] = u;posA[u] = idx;
    }
    void dfsb(int u) {
        vector<int> son;son.clear();
        for(int i = head[u] ; i ; i = E[i].next) {
            int v = E[i].to;son.pb(v);
        }
        reverse(son.begin(),son.end());
        for(int i = 0 ; i < son.size() ; ++i) dfsb(son[i]);
        LB[++idx] = u;posB[u] = idx;
    }
    void DP(int *L,int *p,int *f) {
        for(int i = 1 ; i <= Ncnt ; ++i) {
            int u = L[i];
            int *f1 = f + (i - 1) * (K + 1),*f2 = f + i * (K + 1);
            memcpy(f2,f + (p[u] - siz[u]) * (K + 1),sizeof(int) * (K + 1));
            if(u <= N) {
                for(int j = 1 ; j <= K ; ++j) f2[j] = max(f2[j],f1[j - 1] + v[u]);
            }
            else {
                Q1[ql = qr = 1] = 0;Q2[1] = 0;
                for(int j = 1 ; j <= K ; ++j) {
                    while(ql <= qr && j - Q1[ql] > a[u]) ++ql;
                    if(ql <= qr) f2[j] = max(f2[j],Q2[ql] + j * v[u]);
                    while(ql <= qr && f1[j] - j * v[u] >= Q2[qr]) --qr;
                    Q2[++qr] = f1[j] - j * v[u];Q1[qr] = j;
                }
            }
        }
    }
    void Init() {
        memset(head,0,sizeof(head));
        memset(lef,0,sizeof(lef));
        sumE = 0;tot = 0;
        memset(f,0,sizeof(int) * Ncnt * (K + 1));
        memset(g,0,sizeof(int) * Ncnt * (K + 1));
        read(N);read(K);
        Ncnt = N;
        for(int i = 1 ; i <= N ; ++i) {
            read(fa[i]);read(a[i]);read(v[i]);
            if(fa[i] != 0) add(fa[i],i);
            lef[fa[i]] = 1;
            tot += a[i];
            if(a[i] > 1) {
                add(i,++Ncnt);fa[Ncnt] = i;v[Ncnt] = v[i];a[Ncnt] = a[i] - 1;a[i] = 1;
            }
        }
        idx = 0;dfsa(1);
        idx = 0;dfsb(1);
    }
    void Solve() {
        DP(LA,posA,f);
        DP(LB,posB,g);
        int ans = 0;
        for(int u = 1 ; u <= N ; ++u) {
            if(!lef[u]) {
                int *df = f + (K + 1) * (posA[u] - 1),*dg = g + (K + 1) * (posB[u] - siz[u]);
                int64 cur = min((int64)K,tot - dep[u]);
                for(int j = 0 ; j <= cur ; ++j) {
                    ans = max(ans,df[j] + dg[cur - j] + sumv[u]);
                }
            }
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        int T;
        read(T);
        while(T--) {
            Init();
            Solve();
        }
        return 0;
    }
    

    感觉一看到SDOI R2自动降智
    这么难的省选题要是我去考根本考不动啊

  • 相关阅读:
    django之contenttype
    __new__ 与 __init__的区别
    __getattr__ 与 __getattribute__的区别
    wsgi 简介
    restframework
    ASPxGridView改变列颜色
    C#导出带有格式的Excel(列宽,合并单元格,显示边框线,加背景颜色等)
    c#创建、保存excel正常执行
    C# 导出 Excel 和相关打印设置
    C#命名空间“Microsoft.Office”中不存在类型或命名空间名称的终极解决方法
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9737389.html
Copyright © 2020-2023  润新知