[luoguP3729]曼哈顿计划EX

来自FallDream的博客,未经允许,请勿转载,谢谢。


 

  • 艾登拥有一个计算机网络,每一台计算机都至少有着Intel Xeon E50 v40 + 40路GTX10800Titan的恐怖配置,并由无线网络直接或间接连接,这可以用一个无向连通图来表示。但是他的计算机网络有一个问题——不够安全,dedsec可能会攻击他的网络,切断一些无线连接,从而导致整个计算机网络不连通。为了避免这种情况,艾登决定从这些计算机中挑出一些计算机作为计算节点,其他计算机作为信息的中转站,进行停止核弹发射进程的任务。虽然台台都是顶配,但是艾登的计算机也会有从山寨厂买回的配件和原装正版配件的差别——每台电脑的工作能力是不同的,记为。现在艾登想知道,对于一个工作能力的要求,整个网络的安全系数最大是多少?

  • 设给出的图为,其中 = (计算节点) + (中转节点)

  • 我们定义安全系数k为:最大的k,使得任意两点都至少有k条互不相交的u到v的链(互不相交定义为:没有重复的边,可以重复有重复的点)

  • 我们定义整个图的工作能力

 

先建出等价流树/最小割树,然后按照流量排序,从大到小加入带权并查集,更新答案即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define MN 550
#define MM 3000
#define MV 1000000
#define pa pair<int,int>
#define mp(x,y) make_pair(x,y)
#define INF 2000000000
using namespace std;
inline 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;
}

vector<int> v[MN*10];
bool in[MN+5];
int n,m,Q,cc=0,cnt=1,tot=1,head[MN+5],S,T,fa[MN+5],d[MN+5];
int c[MN+5],q[MN+5],top,w[MN+5],Hd[MN+5],Ques[MN+5],Ans[MV+5],Fa[MN+5];
pa p[MN+5];
struct edge{int to,next,w,tot;}e[MM*10+5];

inline void ins(int*H,int f,int t,int w)
{
    e[++cnt]=(edge){t,H[f],w,w};H[f]=cnt;
    e[++cnt]=(edge){f,H[t],w,w};H[t]=cnt;
}    

void Get(int x)
{
    in[x]=1;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].w&&!in[e[i].to]) Get(e[i].to);
}

int dfs(int x,int f)
{
    if(x==T) return f;
    int used=0;
    for(int&i=c[x];i;i=e[i].next)
        if(e[i].w&&d[e[i].to]==d[x]+1)
        {
            int w=dfs(e[i].to,min(f-used,e[i].w));
            used+=w;e[i].w-=w;e[i^1].w+=w;
            if(used==f) return f; 
        } 
    return d[x]=-1,used;
}

bool bfs()
{
    memset(d,0,sizeof(d));int i,j;
    for(d[q[top=i=1]=S]=1;i<=top;++i)
        for(j=c[q[i]]=head[q[i]];j;j=e[j].next)
            if(e[j].w&&!d[e[j].to])
                d[q[++top]=e[j].to]=d[q[i]]+1;
    return d[T];
}

void Solve(int x)
{
    if(v[x].size()<2) return;
    S=v[x][0],T=v[x][1];int ans=0;
    for(int i=2;i<=cnt;++i) e[i].w=e[i].tot;
    while(bfs()) ans+=dfs(S,INF); 
    ins(Hd,S,T,ans);
    memset(in,0,sizeof(in));Get(S);
    for(int i=0;i<v[x].size();++i)
        v[tot+1+in[v[x][i]]].push_back(v[x][i]);
    int pre=tot;tot+=2;Solve(pre+1);Solve(pre+2);
}

void Dfs(int x,int fa)
{
    for(int i=Hd[x];i;i=e[i].next)
        if(e[i].to!=fa&&e[i].w) Fa[e[i].to]=x,p[++cc]=mp(e[i].w,e[i].to),Dfs(e[i].to,x);
}
inline int getfa(int x){return fa[x]?fa[x]=getfa(fa[x]):x;}
int main()
{
    n=read();m=read();Q=read();int mx=0;
    for(int i=1;i<=n;++i) mx=max(mx,w[i]=read()),v[1].push_back(i);
    for(int i=1;i<=m;++i)
    {
        int x=read(),y=read();
        ins(head,x,y,1);
    }
    Solve(1);Dfs(1,0);
    sort(p+1,p+cc+1,greater<pa>());
    for(int i=1;i<=cc;++i)
    {
        int x=p[i].second,y=getfa(Fa[x]);
        fa[x]=y;w[y]+=w[x];
        Ans[min(w[y],MV)]=max(Ans[min(MV,w[y])],p[i].first);
    }
    for(int i=MV;i;--i)
        Ans[i]=max(Ans[i],Ans[i+1]);
    for(int i=1;i<=Q;++i)
    {
        int x=read();    
        if(x<=mx) puts("nan");
        else if(Ans[x]) printf("%d\n",Ans[x]);
        else puts("Nuclear launch detected");
    }
    return 0;
}

 

posted @ 2017-05-25 16:47  FallDream  阅读(308)  评论(0编辑  收藏  举报