JZOJ6346ZYB和售货机

Posted horizonwd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JZOJ6346ZYB和售货机相关的知识,希望对你有一定的参考价值。

description

技术图片


analysis

  • 其实这个连出来的东西叫基环内向树

  • 先考虑很多森林的情况,也就是树根连回自己

  • 明显树根物品是可以被取完的,那么买树根的价钱要是儿子中价钱最小的那个

  • 或者把那个叫成收益,也就是选择所有儿子中收益最大的儿子

  • 既然树根可以取完,同理所有非叶子节点也可以被取完

  • 所以树(森林)的情况就可以\\(O(n)\\)遍历一遍得到

  • 考虑在基环树上删去一条边,使得图变成树,然后用树的做法

  • 如果购买一个点的父亲\\(x\\),卖钱比另一个父亲也为\\(x\\)的要差,那就不用按按钮

  • 没有这种情况,就钦定环上环边贡献减去树边贡献最小的点断开环边

  • 记录每个点的儿子中收益最大和次大的儿子,就可以知道两个贡献之差


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 100005
#define MAXM MAXN*2
#define ha 19260817
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=last[a];i;i=next[i])

using namespace std;

ll last[MAXM],next[MAXM],tov[MAXM];
ll fa[MAXN],a[MAXN],c[MAXN],d[MAXN];
ll dfn[MAXN],num[MAXN],val[MAXN],mx[MAXN],smx[MAXN];
ll bz[MAXN],flag[MAXN];
ll n,mn=ha,tot,ans,where;

inline ll read()

    ll x=0,f=1;char ch=getchar();
    while (ch<'0' || '9'<ch)if (ch=='-')f=-1;ch=getchar();
    while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;

inline ll max(ll x,ll y)return x>y?x:y;
inline ll min(ll x,ll y)return x<y?x:y;
inline void link(ll x,ll y)next[++tot]=last[x],last[x]=tot,tov[tot]=y;
/*
inline void findcircle(ll x)

    if (dfn[x]==tot)
    
        fo(i,1,n)if (dfn[x]==tot)bz[i]=1;
        return;
    
    if (dfn[x])return;
    dfn[x]=tot;if (x!=fa[x])findcircle(fa[x]);

inline void dfs(ll x)

    ans+=val[mx[x]]*a[x];
    rep(i,x)dfs(tov[i]);
*/

inline void dfs1(ll x)

    if (flag[x]==tot)ans-=mn;return;
    if (flag[x])return;
    flag[x]=tot,mn=min(mn,val[mx[x]]-val[smx[x]]);
    if (mx[x]!=x)dfs1(mx[x]);


int main()

    //freopen("T2.in","r",stdin);
    freopen("goods.in","r",stdin);
    freopen("goods.out","w",stdout);
    n=read();
    fo(i,1,n)fa[i]=read(),c[i]=read(),d[i]=read(),a[i]=read(),link(fa[i],i);
    fo(i,1,n)
    
        val[i]=d[fa[i]]-c[i];
        if (val[i]<0)continue;
        if (val[i]>val[mx[fa[i]]])smx[fa[i]]=mx[fa[i]],mx[fa[i]]=i;
        else if (val[i]>val[smx[fa[i]]])smx[fa[i]]=i;
    
    tot=0;
    //fo(i,1,n)if (!dfn[i])++tot,findcircle(i);
    fo(i,1,n)ans+=val[mx[i]]*a[i];
    tot=0;
    fo(i,1,n)if (!flag[i])++tot,mn=ha,dfs1(i);
    printf("%lld\\n",ans);
    return 0;

以上是关于JZOJ6346ZYB和售货机的主要内容,如果未能解决你的问题,请参考以下文章

[JZOJ6345]:ZYB建围墙(数学+构造)

jzoj4020

jzoj4020

JZOJ3966 Sabotage 题解

JZOJ 1321. 灯

[solution] JZOJ-5458 质数