【JZOJ6346】ZYB和售貨機

description


analysis

  • 其實這個連出來的東西叫基環內向樹

  • 先考慮很多森林的情況,也就是樹根連回自己

  • 明顯樹根物品是可以被取完的,那麼買樹根的價錢要是兒子中價錢最小的那個

  • 或者把那個叫成收益,也就是選擇所有兒子中收益最大的兒子

  • 既然樹根可以取完,同理所有非葉子節點也可以被取完

  • 所以樹(森林)的情況就可以O(n)O(n)遍歷一遍得到

  • 考慮在基環樹上刪去一條邊,使得圖變成樹,然後用樹的做法

  • 如果購買一個點的父親xx,賣錢比另一個父親也爲xx的要差,那就不用按按鈕

  • 沒有這種情況,就欽定環上環邊貢獻減去樹邊貢獻最小的點斷開環邊

  • 記錄每個點的兒子中收益最大和次大的兒子,就可以知道兩個貢獻之差


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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章