电报

来源:互联网 发布:淘宝一元抢购在哪里 编辑:程序博客网 时间:2024/05/17 08:30

题目大意

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);}
原创粉丝点击