题目大意
n个点,每个点出度均为1的有向图。
你可以将j->k改成j->l,代价为c[j]。
求最小代价,使得有向图变成一个环。
贪心
我们把问题描述成删去若干条边,删除每条边都有代价,最小代价使得每个联通块都是一条链(这样才能连成环)。
假如一个点有k个入度,至少k-1个要被删掉。
对于树的情况贪心保留最大代价的入边。
环上至少一条边要删去,再讨论一下即可。
注意特判初始所有点连成一个环的情况。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100000+10,inf=2000000000;
int a[maxn],b[maxn],c[maxn],g[maxn],p[maxn],belong[maxn];
int h[maxn],go[maxn],nxt[maxn];
int h2[maxn],g2[maxn],n2[maxn];
ll f[maxn];
bool pd[maxn],bz[maxn];
int i,j,k,l,t,n,m,tot,top,cnt,wdc,mi;
ll ans,sum,num;
bool czy;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void add(int x,int y){
go[++tot]=y;
nxt[tot]=h[x];
h[x]=tot;
}
void add2(int x,int y){
g2[++cnt]=y;
n2[cnt]=h2[x];
h2[x]=cnt;
}
void dfs(int x){
if (pd[a[x]]){
belong[x]=++tot;
bz[x]=1;
wdc=a[x];
return;
}
if (belong[a[x]]){
belong[x]=belong[a[x]];
return;
}
pd[x]=1;
dfs(a[x]);
belong[x]=belong[a[x]];
if (wdc) bz[x]=1;
if (x==wdc) wdc=0;
pd[x]=0;
}
void dg(int x){
int t=h[x],mx=0;
ll l=0;
while (t){
dg(go[t]);
mx=max(mx,c[go[t]]);
l+=(ll)c[go[t]];
t=nxt[t];
}
ans+=(ll)l-mx;
}
void work(int x){
top=0;
t=h2[x];
while (t){
p[++top]=g2[t];
t=n2[t];
}
fo(i,1,top)
if (!bz[p[i]]&&bz[a[p[i]]]){
dg(p[i]);
f[a[p[i]]]+=(ll)c[p[i]];
g[a[p[i]]]=max(g[a[p[i]]],c[p[i]]);
}
fo(i,1,top)
if (bz[p[i]]) b[a[p[i]]]=c[p[i]];
mi=inf;
fo(i,1,top)
if (bz[p[i]]) mi=min(mi,c[p[i]]);
sum=0;
fo(i,1,top)
if (bz[p[i]]) sum+=f[p[i]];
num=sum+mi;
sum=0;
fo(i,1,top)
if (bz[p[i]]) sum+=min(f[p[i]],f[p[i]]-g[p[i]]+(ll)b[p[i]]);
fo(i,1,top)
if (bz[p[i]]){
sum-=min(f[p[i]],f[p[i]]-g[p[i]]+(ll)b[p[i]]);
num=min(num,sum+f[p[i]]-g[p[i]]+(ll)b[p[i]]);
sum+=min(f[p[i]],f[p[i]]-g[p[i]]+(ll)b[p[i]]);
}
ans+=num;
}
int main(){
freopen("telegraph.in","r",stdin);freopen("telegraph.out","w",stdout);
n=read();
fo(i,1,n){
a[i]=read();c[i]=read();
add(a[i],i);
}
tot=0;
fo(i,1,n)
if (!belong[i]){
wdc=0;
dfs(i);
}
if (tot==1){
czy=1;
fo(i,1,n)
if (!bz[i]){
czy=0;
break;
}
if (czy){
printf("0\n");
return 0;
}
}
fo(i,1,n) add2(belong[i],i);
fo(wdc,1,tot) work(wdc);
printf("%lld\n",ans);
}