BZOJ2521: [Shoi2010]最小生成树

来源:互联网 发布:java中逻辑或 编辑:程序博客网 时间:2024/05/20 07:15

BZOJ2521

QAQ一开始看到这个题就想到了BZOJ2561
然而瞬间否定,这两个题应该不太一样。神flag
先说说一开始错的想法错在哪吧。。
可以直接pass
(一开始想的是类似次小生成树的做法,先做最小生成树,排序时若有多个边长与z[lab]相同的边,把lab放到最后,然后MST,如果边lab没出现,直接返回。然而发现这样还是有可能有其他解使得不考虑边lab,MST答案也相同,那就不考虑该边再做一次,如果MST>MST,就直接输出0。然后枚举边lab的两个端点,找一条树链间的最长边mx,然后答案=z[lab]z[mx]+1。。然而自己还是太naive。。非树边也可能对答案有影响啊QAQ。蠢得一批。)

那正确的做法其实就和2561差不多啦。一次操作相当于给一条边边权+1,那么显然只会给边权<=z[lab]的边加。那么就是要求所有原边权<=z[lab]的边加入到最小生成树后x[lab]y[lab]仍然不连通。那么考虑最小割,对于所有i!=Lab && z[i]<=z[Lab]的边,连边(x[i],y[i],z[Lab]z[i]+1),表示割去这条边的代价。
答案就是最小割。

【代码】

#include <cstdio>#include <iostream>#include <algorithm>#include <queue>#define N 505#define M 1605#define INF 0x7fffffffusing namespace std;typedef long long ll;ll read(){    ll x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}    return x*f;}int n,m,Lab,cnt=1,S,T;int b[M],p[N],nextedge[M],w[M],cur[N];int Level[N],x[M],y[M],z[M];void Add(int x,int y,int z){    cnt++;    b[cnt]=y;    nextedge[cnt]=p[x];    p[x]=cnt;    w[cnt]=z;}void Anode(int x,int y,int z){    Add(x,y,z);Add(y,x,z);}bool Bfs(){    queue<int>q;    q.push(S);    for(int i=1;i<=n;i++) Level[i]=0;    Level[S]=1;    while(!q.empty())    {        int k=q.front();q.pop();        for(int i=p[k];i;i=nextedge[i])        {            int v=b[i];if(!Level[v]&&w[i])            {                Level[v]=Level[k]+1;                q.push(v);            }        }    }    return Level[T];}int Dfs(int x,int maxf){    if(x==T||!maxf) return maxf;    int rtn=0;    for(int i=cur[x];i&&maxf>rtn;i=nextedge[i])    {        int v=b[i],f=w[i];        if(Level[v]==Level[x]+1&&f)        {            f=Dfs(v,min(maxf-rtn,f));            w[i]-=f;w[i^1]+=f;            rtn+=f;if(w[i]) cur[x]=i;        }    }    if(!rtn) Level[x]=0;    return rtn;}void Dinic(){    int rtn=0;    while(Bfs()) {        for(int i=1;i<=n;i++) cur[i]=p[i];        rtn+=Dfs(S,INF);    }       printf("%d\n",rtn);}int main(){    n=read(),m=read(),Lab=read();    for(int i=1;i<=m;i++)        x[i]=read(),y[i]=read(),z[i]=read();    S=x[Lab],T=y[Lab];    for(int i=1;i<=m;i++) if(i!=Lab&&z[i]<=z[Lab]) Anode(x[i],y[i],z[Lab]-z[i]+1);    Dinic();    return 0;}