zoukankan      html  css  js  c++  java
  • 题解 洛谷 P3642 【[APIO2016]烟火表演】

    (f_i(x)) 为以节点 (i) 为根的子树都以时刻 (x) 爆炸的最小代价,发现其为一个下凸的分段函数,即为一个下凸包。

    考虑一个节点加上其与父节点的边后函数的变化,设原函数的最小值为 (f_{min}),取到最小值的区间为 ([l,r]),与父节点的边的边权为 (v),得:

    [{f}'(x) = egin{cases} f(x) + v & x leqslant l \ f_{min} + l + v - x & l < x leqslant l + v \ f_{min} & l + v < x leqslant r + v \ f_{min} + x - r - v & r + v < x end{cases} ]

    发现和原函数对比,加上这条边后,函数的变化为向上平移左边的一段,然后加入三段斜率分别为 (-1,0,1) 的函数。对于一个节点,其所有儿子的新函数合并后的函数,即为该节点对应的函数。因为是合并起来的,所以该分段函数的每一段的斜率的差为 (1),最小值右边的函数段数为其儿子个数。

    对于函数,只需维护其端点位置即可,因为需要合并和删除,所以用可并堆来维护,我这里用的是左偏树。得 (f_{root}(0)) 为所有边权和,结合端点位置,即可计算最小值。

    (code:)

    #include<bits/stdc++.h>
    #define maxn 600010
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,tot;
    ll ans;
    int fa[maxn],rt[maxn],ls[maxn],rs[maxn],dis[maxn],son[maxn];
    ll v[maxn],val[maxn];
    int merge(int x,int y)
    {
        if(!x||!y) return x+y;
        if(val[x]<val[y]) swap(x,y);
        rs[x]=merge(rs[x],y);
        if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
        if(rs[x]) dis[x]=dis[rs[x]]=1;
        else dis[x]=0;
        return x;
    }
    int del(int x)
    {
        return merge(ls[x],rs[x]);
    }
    int main()
    {
        read(n),read(m);
        for(int i=2;i<=n+m;++i)
            read(fa[i]),read(v[i]),son[fa[i]]++,ans+=v[i];
        for(int i=n+m;i>1;--i)
        {
            ll l=0,r=0;
            if(son[i])
            {
                for(int j=1;j<son[i];++j) rt[i]=del(rt[i]);
                l=val[rt[i]],rt[i]=del(rt[i]);
                r=val[rt[i]],rt[i]=del(rt[i]);
            }
            val[++tot]=l+v[i],rt[i]=merge(rt[i],tot);
            val[++tot]=r+v[i],rt[i]=merge(rt[i],tot);
            rt[fa[i]]=merge(rt[fa[i]],rt[i]);
        }
        while(son[1]--) rt[1]=del(rt[1]);
        while(rt[1]) ans-=val[rt[1]],rt[1]=del(rt[1]);
        printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    数据结构(动态树):UOJ 207 共价大爷游长沙
    字符串(后缀自动机):NOI 2016 优秀的拆分
    数学(矩阵乘法):HDU 4565 So Easy!
    数据结构(线段树):NOI 2016 区间
    动态规划:NOI2013 快餐店
    图论(网络流):UVa 1659
    数学(矩阵乘法,随机化算法):POJ 3318 Matrix Multiplication
    数学(莫比乌斯反演):YY的GCD
    数学(莫比乌斯反演):HAOI 2011 问题B
    字符串(后缀自动机):USACO Dec10 恐吓信
  • 原文地址:https://www.cnblogs.com/lhm-/p/13449231.html
Copyright © 2011-2022 走看看