• sdoi2017苹果树


    题解:

    非常奇妙的一题。。

    没有免费操作我都不会$nk$。。。。考试打个暴力就可以走人了

    树上有依赖背包问题的正确做法是(为啥我之前学的不是这样的啊)

    按照后续遍历做背包

    做到一个点的时候 枚举它选不选 不选只能从子树外转移 选的话可以从x-1转移

    而不是对每个点求一次$f[i][j]$ 这样是$n*k^2$

    前者不管是多重背包还是0/1背包 复杂度都是$nk$的(单调队列优化)

    将题目给的条件转化,变成有一条链是免费

    我们会发现这样求出的路径是它到根的路径的左边和自己子树的背包

    那么我们可以想到 如果按照右左根再遍历一遍 可以得到右边+自己子树的背包

    另外有一个性质就是,这条链一定会到叶子

    而我们发现对于叶子两个背包合并的话就只多算了当前点并且当前点到根这一段都没有算(只要把一个编号右移一位就没有重复了)

    这恰好符合了题目的免费操作

    但是注意那些点ai是可以>1也就是说还需要考虑付费部分

    一种直观的思路是对其中一种dfs子儿子之前先把$(ai-1,vi)$作为一种物品放进去

    其实这等价于再加一个$(ai-1,vi)$的儿子

    然后这样就可以卡着空间过了。。 因为多加了儿子,数组需要2.5e7*2*2

    ***常数巨大但洛谷评测机快就过了

    单调队列里面一堆变量写错。。

    数组大小一堆开错。。然后查错查了一个小时。。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for(int i=h;i<=t;i++)
    #define dep(i,t,h) for(int i=t;i>=h;i--)
    #define ll long long
    #define me(x) memset(x,0,sizeof(x))
    #define mep(x,y) memcpy(x,y,sizeof(y))
    #define mid (t<=0?(h+t-1)/2:(h+t)/2)
    namespace IO{
        char ss[1<<24],*A=ss,*B=ss;
        IL char gc()
        {
            return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;
        }
        template<class T> void read(T &x)
        {
            rint f=1,c; while (c=gc(),c<48||c>57) if (c=='-') f=-1; x=(c^48);
            while (c=gc(),c>47&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; 
        }
        char sr[1<<24],z[20]; int Z,C1=-1;
        template<class T>void wer(T x)
        {
            if (x<0) sr[++C1]='-',x=-x;
            while (z[++Z]=x%10+48,x/=10);
            while (sr[++C1]=z[Z],--Z);
        }
        IL void wer1()
        {
            sr[++C1]=' ';
        }
        IL void wer2()
        {
            sr[++C1]='
    ';
        }
        template<class T>IL void maxa(T &x,T y) {if (x<y) x=y;}
        template<class T>IL void mina(T &x,T y) {if (x>y) x=y;} 
        template<class T>IL T MAX(T x,T y){return x>y?x:y;}
        template<class T>IL T MIN(T x,T y){return x<y?x:y;}
    };
    using namespace IO;
    const int N=6e5;
    const int N2=51000000;
    int n,k,ans[N],a[N],v[N],dp1[N2],dp2[N2],sum[N],cnt;
    int dfn1[N],dfn2[N];
    vector<int> ve[N];
    struct re{
        int a,b;
    }p[N];
    void dfs1(int x)
    {
        sum[x]=1;
        for (int i=0;i<ve[x].size();i++)
        {
            ans[ve[x][i]]=ans[x]+v[x];
            dfs1(ve[x][i]);
            sum[x]+=sum[ve[x][i]];
        }
        dfn1[x]=++cnt;
        int n1=dfn1[x]-1,k1=n1*(k+1);
        int k2=dfn1[x]*(k+1);
        int h=1,t=0; p[1]=(re){0,0};
        rep(i,0,k)
        {
            if (h<=t&&(i-p[h].a)>a[x]) h++;
            if (h<=t) dp1[k2+i]=v[x]*i+p[h].b;
            int now=dp1[k1+i]-v[x]*i;
            while (h<=t&&now>=p[h].b) t--;
            p[++t]=(re){i,now};
        }
        n1=dfn1[x]-sum[x],k1=n1*(k+1);
        rep(i,0,k)
        { 
          dp1[k2+i]=MAX(dp1[k2+i],dp1[k1+i]);
          if (i) maxa(dp1[k2+i],dp1[k2+i-1]);
        }
    }
    bool vis[N];
    void dfs2(int x)
    {
        vis[x]=1;
        sum[x]=1;
        for (int i=(int)(ve[x].size())-1;i>=0;i--)
        {
            dfs2(ve[x][i]);
            sum[x]+=sum[ve[x][i]];
        }
        dfn2[x]=++cnt;
        int n1=dfn2[x]-1,k1=n1*(k+1);
        int k2=dfn2[x]*(k+1);
        int h=1,t=0; p[1]=(re){0,0};
        rep(i,0,k)
        {
            if (h<=t&&(i-p[h].a)>a[x]) h++;
            if (h<=t) dp2[k2+i]=v[x]*i+p[h].b;
            int now=dp2[k1+i]-v[x]*i;
            while (h<=t&&now>=p[h].b) t--;
            p[++t]=(re){i,now};
        }
        n1=dfn2[x]-sum[x],k1=n1*(k+1);
        rep(i,0,k)
        { 
          dp2[k2+i]=MAX(dp2[k2+i],dp2[k1+i]);
          if (i) maxa(dp2[k2+i],dp2[k2+i-1]);
        }
    }
    int main()
    {
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
        int T;
        read(T);
        rep(ttt,1,T)
        {
            read(n); read(k); me(dp1); me(dp2);
            rep(i,0,N-1)
            {
                vector<int> v2;
                v2.swap(ve[i]);
            }
            rep(i,1,n) 
            {
              int x; read(x);
              read(a[i]); read(v[i]);
              if (x) ve[x].push_back(i);
              a[i+n]=a[i]-1,v[i+n]=v[i];
              a[i]=1;
              ve[i].push_back(i+n);
            }
            cnt=0; dfs1(1);
            cnt=0; dfs2(1);
            int num=0;
            rep(i,n+1,2*n)
              rep(j,0,k) 
              maxa(num,ans[i]+dp1[dfn1[i]*(k+1)+j]
              +dp2[(dfn2[i]-1)*(k+1)+k-j]);
            cout<<num<<endl;
        }
        return 0;
    }
  • 相关阅读:
    自己写的基类:Forms身份验证类、客户端事件类,序列化类下载
    毕业设计上线啦!跳蚤部落与基于Comet的WebIM系统开发
    域名解析碎片整理 《不同的子域名解析到同一服务器下不同的网站》
    Mac 命令行大全
    position 事件 zindex
    vue 微信公众号网页开发 跳转小程序 踩坑
    React 笔记
    我对架构师的理解(如何成为一个合格的架构师)
    听过我爸是李刚,你听说过我妈是上海人不?
    Lucene.NET打造站内搜索引擎
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/10057559.html
Copyright © 2020-2023  润新知