题目描述
可爱的 Z Y B ZYB ZYB来到一个售货机前。
售货机里有一共有
N
(
≤
1
0
5
)
N(≤10^5)
N(≤105)个物品,每个物品有
A
i
A_{i}
Ai个。
自然,还有
N
N
N个购买按钮。正常情况下,按下第i个按钮,需要支付
C
i
C_{i}
Ci的钱,然后会跳出一份物品
i
i
i。
如果该物品卖完了,按下此按钮无效。
但是,这台售货机的电路连接出了点问题。第i个按钮的“弹出电路”连向了物品fi。
假设按下了第 i i i个按钮,售货机会按以下逻辑执行:
-
判断第 i i i个物品是否为空。
-
如果是,不执行任何操作,退出该购买程序。
-
否则,要求支付 C i C_{i} Ci的钱。
-
因为电路坏了,实际弹出的物品会是 f i f_{i} fi。
注意:如果物品 f i f_{i} fi为空,显然也不会有物品弹出。
Z Y B ZYB ZYB很快发现了售货机的秘密,并精确掌握了 f i f_{i} fi的值。他又去调查了每一种物品的市场价。即他可以以 D i D_{i} Di的价格卖掉物品 i i i。
现在 Z Y B ZYB ZYB他想通过这台售货机,赚尽量多的钱。
假设 Z Y B ZYB ZYB有足够多的成本钱。
输入
第一行一个数
N
N
N,表示售货机里的物品总数。
接下来有
N
N
N行,每行有四个数
f
i
,
C
i
,
D
i
,
A
i
fi,Ci,Di,Ai
fi,Ci,Di,Ai,意义同上。
输出
输出一个数表示最大获利。
样例输入
样例输入1
3
1 2 3 1
2 3 4 1
3 4 5 1
样例输入2
3
2 2 3 8
3 1 5 6
1 4 4 7
样例输出
样例输出1
3
样例输出2
39
提示
前
10
%
10\%
10%
N
≤
5
,
∏
i
=
N
(
A
i
+
1
)
≤
105
N≤5,∏i=N(A_{i}+1)≤105
N≤5,∏i=N(Ai+1)≤105
前
30
%
30\%
30%:
N
≤
10
N≤10
N≤10
前
50
%
50\%
50%:
N
≤
200
N≤200
N≤200
另有
10
%
10\%
10%:
f
i
=
i
f_{i}=i
fi=i
另有
10
%
10\%
10%:
f
i
≤
i
f_{i}≤i
fi≤i
另有
10
%
10\%
10%:
a
i
=
1
a_{i}=1
ai=1
100
%
100\%
100%:
1
≤
N
≤
1
0
5
,
1
≤
f
i
≤
N
,
C
i
≤
D
i
,
1
≤
C
i
,
D
i
,
A
i
≤
1
0
6
1≤N≤10^5,1≤f_{i}≤N,C{i}≤D_{i},1≤C_{i},D_{i}, A_{i}≤10^6
1≤N≤105,1≤fi≤N,Ci≤Di,1≤Ci,Di,Ai≤106
题解
考虑先建图,由
i
i
i连向
f
i
f_{i}
fi,出来是个边数与点数相同的基环内向树。
于是考虑搞掉那个环。
经过深思熟虑可得,如果存在环上的一个点
x
x
x,按下这个按钮获得的收益不如另一条连向
f
x
f_{x}
fx 的树边,
如果不存在这样的点,那么我们就找一个环边价值和树边价值的差最小的点,强制它不能选择环边,统计答案即可。
实际上,我们只要记录到每个节点的最大和次大的边。
D
F
S
DFS
DFS过程中,默认接上最大边的值,维护最大边和次大边的差的最小值。找到环之后,我们显然要断掉环——使连向某个点的边改变(从默认的最大变成次大),此时只要减去维护的最小值即可。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<bits/stdc++.h>
using namespace std;
#define in inline
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=1e6+4;
typedef long long ll;
int c[N],a[N],d[N],v[N],smx[N],fa[N],mx[N];
int pos,dfn[N],mn,n; ll ans;
in void dfs(int x){
if(dfn[x]==pos){ans-=mn;return;}
if(dfn[x]) return;
dfn[x]=pos;
if(mx[x]){
ans+=1ll*v[mx[x]]*a[x];
mn=min(mn,v[mx[x]]-v[smx[x]]);
if(mx[x]!=x) dfs(mx[x]);
}
}
int main(){
//freopen(".in","r",stdin);freopen(".out","w",stdout);
g(n);
rep(i,1,n) g(fa[i]),g(c[i]),g(d[i]),g(a[i]);
rep(i,1,n){
v[i]=d[fa[i]]-c[i];
if(v[i]<0) continue;
if(v[i]>v[mx[fa[i]]]){
smx[fa[i]]=mx[fa[i]];
mx[fa[i]]=i;
}
else if(v[i]>v[smx[fa[i]]]) smx[fa[i]]=i;
}
rep(i,1,n){
if(!dfn[i])
mn=1e9,++pos,dfs(i);
}
printf("%lld\n",ans);
return 0;
}