BZOJ 3691 游行

题目传送门

分析:

没被访问的点要C费用,跑一次路要C费用

把这两个统一一下试试。。。

那就是每次不标记起点或者终点

那就是路径覆盖了2333

二分图,x 部 i 号点与 y 部 j 号点连 i 到 j 的最短路

然后每个点都会被访问到

但是有些的代价会大于C

那些就干脆不访问了吧2333

看看费用流的函数特征

是一个单增函数

某一刻一单位流的代价大于了C,那就可以停止了

由于C会变,先求出整个的费用流函数,每次二分查找就好了

BZOJ 3691 游行
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>

#define maxn 2005
#define maxm 200005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

int n,m,Q;
int S,T;
int fir[maxn],nxt[maxm],to[maxm],cnt;
int cap[maxm],cst[maxm];
int dis[maxn];
int vis[maxn],pre[maxn];
int sum[maxn],tot;
int D[maxn][maxn];

inline void newnode(int u,int v,int w,long long c)
{to[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,cap[cnt]=w,cst[cnt]=c;}
inline void insert(int u,int v,int w,long long c)
{newnode(u,v,w,c),newnode(v,u,0,-c);}

inline bool spfa()
{
    memset(dis,INF,sizeof dis);dis[S]=0;
    memset(pre,-1,sizeof pre);
    queue<int>Q;Q.push(S),vis[S]=1;
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();vis[u]=0;
        for(int i=fir[u];i;i=nxt[i])
            if(cap[i]&&dis[to[i]]>dis[u]+cst[i])
            {
                dis[to[i]]=dis[u]+cst[i];pre[to[i]]=i^1;
                if(!vis[to[i]])vis[to[i]]=1,Q.push(to[i]);
            }
    }
    return ~pre[T];
}

inline int dinic()
{
    int num=0;
    while(spfa())
    {
        tot++;
        sum[tot]=sum[tot-1];
        int mn=INF;
        for(int i=pre[T];i!=-1;i=pre[to[i]])mn=min(mn,cap[i^1]);
        int tmp=0;
        for(int i=pre[T];i!=-1;i=pre[to[i]])cap[i]+=mn,cap[i^1]-=mn,tmp+=cst[i^1];
        sum[tot]+=tmp*mn,num+=mn;
    }
    return num;
}

int main()
{
    n=getint(),m=getint(),Q=getint();
    S=n*2+1,T=S+1,cnt=1;
    memset(D,INF,sizeof D);
    for(int i=1;i<=n;i++)D[i][i]=0;
    for(int i=1;i<=m;i++)
    {
        int u=getint(),v=getint();
        D[u][v]=min(getint(),D[u][v]);
    }
    for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
        D[i][j]=min(D[i][j],D[i][k]+D[k][j]);
    for(int i=1;i<=n;i++)insert(S,i,1,0),insert(i+n,T,1,0);
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(i^j)insert(i,j+n,1,D[i][j]);
    dinic();
    while(Q--)
    {
        int C=getint(),l=1,r=tot,ans=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(sum[mid]-sum[mid-1]<C)l=mid+1,ans=mid;
            else r=mid-1;
        }
        printf("%d\n",sum[ans]+(n-ans)*C);
    }
}
View Code

BZOJ 3691 游行

上一篇:[THUSC2016]成绩单 [区间dp]


下一篇:【刷题】【单调栈】请客