CF1383F. Special Edges

发布时间 2023-05-21 01:54:10作者: gmh77

题目大意

给出一个有向图,有k条特殊边,每条边每次询问指定容量

求每次询问的最大流

n,m<=1e4,k<=10,q<=2e5,边权w<=25

题解

最大流=最小割,所以枚举k条边的割边情况,最大流=最小割=min(枚举的割边+剩余的最小割)

建一个新图求剩余部分的最小割
①非k条边:直接加到新图
②k条中确定割了的边:不加
③k条中确定没割的边:设为inf,因为割这条不如把剩下的都割了,所以不会割

求新图的最小割(最大流)就是剩余的最小割,加上枚举的割边代价就是一组方案


假设k条全部都割了,就是全k条都不加的情况,求出了这种情况的答案和残量网络
然后在这基础上加一条inf边,就可以得到某条边不割的情况,这样只加一条边就可以跑FF算法
(手玩一下发现加边容量为25即可,如果inf边跑了超过25则一定不如确定割掉优,这样一次跑的复杂度就是O(25*m)

具体实现,先跑一遍dinic/sap,然后枚举删边情况,记录上一次的残量网络,每次在上一次的基础上加一条25边跑FF
最后根据询问的wi高维前缀和来算答案

时间O(玄),因为第一次的dinic就理论\(O(n^2m)\)了……

code

没过,卡不动

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define Min(a,b) a=min(a,b)
#define Max(a,b) a=max(a,b)
#define low(x) ((x)&-(x))
#define ll long long
#define inf 1000000
#define st 1
#define ed n
//#define file
using namespace std;

struct type{
	int x,y,z;
};
bool cmp(type a,type b)
{
	return a.x<b.x || a.x==b.x && a.y<b.y;
}

void Read(int &x)
{
	char ch;
	x=0;
	ch=getchar();
	while (!(ch>='0' && ch<='9')) ch=getchar();
	while ( (ch>='0' && ch<='9')) x=x*10+ch-'0',ch=getchar();
}
char St[21];
void Write(int x)
{
	if (!x)
	{
		printf("0\n");
		return;
	}
	int i=0;
	while (x) St[++i]=x%10+'0',x/=10;
	while (i) putchar(St[i]),--i;
	putchar('\n');
}

bool data87=0;
int n,m,K,Q,i,j,k,l,x,y,z;
bool bz_end,bz_p[10001];
int wf[10011],wg[10011];
struct Graph{
	int a[20011][3],ls[10011],cur[10011],len;
	
	void clear()
	{
		memset(ls,0,sizeof(ls)),len=1;
		memcpy(cur,ls,sizeof(ls));
	}
	
	void New(int x,int y,int z)
	{
		++len;
		a[len][0]=y;
		a[len][1]=ls[x];
		ls[x]=cur[x]=len;
		a[len][2]=z;
	}
	
	int dfs_sap(int t,int w)
	{
		int i,v,use=0;
		if (t==ed) {bz_end=1;return w;}
		
		bz_p[t]=1;
		
		for (i=cur[t]; i; i=a[i][1])
		{
			cur[t]=i;
			if (a[i][2] && wf[t]==wf[a[i][0]]+1)
			{
				v=dfs_sap(a[i][0],min(w,a[i][2]));
				a[i][2]-=v;
				a[i^1][2]+=v;
				w-=v;
				use+=v;
				
				if (!w) {bz_p[t]=0;return use;}
			}
		}
		cur[t]=ls[t];
		bz_p[t]=0;
		
		--wg[wf[t]];
		if (wg[wf[t]]==0)
		{
			wf[st]=ed+2;
			return use;
		}
		++wf[t],++wg[wf[t]];
		
		return use;
	}
	
	int dfs(int t,int w)
	{
		int i,v,use=0;
		if (t==ed) {bz_end=1;return w;}
		
		bz_p[t]=1;
		
		for (i=ls[t]; i; i=a[i][1])
		{
			cur[t]=i;
			if (a[i][2] && !bz_p[a[i][0]])
			{
				v=dfs(a[i][0],min(w,a[i][2]));
				if (!v) continue;
				
				a[i][2]-=v;
				a[i^1][2]+=v;
				w-=v;
				use+=v;
				
				return use;
			}
		}
		
		return use;
	}
	
	void Copy(Graph& G0)
	{
		int i,j;
		len=G0.len;
		memcpy(a,G0.a,sizeof(a[0])*(G0.len+1));
		memcpy(ls,G0.ls,4*(n+1));
		memcpy(cur,ls,4*(n+1));
	}
} G[11];
int A[10001][3];
int Ans[1024],sum[1024],ans;
bool bz[11];
int w[11];
vector<type> v;

void G0_init()
{
	G[0].len=1;
	fo(i,K+1,m)
	if (A[i][2]!=-1)
	{
		G[0].New(A[i][0],A[i][1],A[i][2]);
		G[0].New(A[i][1],A[i][0],0);
	}
	n=n;
	memset(wf,0,sizeof(wf));
	memset(wg,0,sizeof(wg));
	memcpy(G[0].cur,G[0].ls,sizeof(G[0].ls));
	wg[0]=ed;
	while (wf[st]<=ed+1)
	Ans[(1<<K)-1]+=G[0].dfs_sap(st,inf);
}

void dg(int t,int s,int Gid,int ans)
{
	int i;
	if (t>K)
	{
		Ans[s]=ans;
		return;
	}
	
	bz[t]=1;A[t][2]=-1;
	dg(t+1,s+(1<<(t-1)),Gid,ans);
	
	G[Gid+1].Copy(G[Gid]);
	G[Gid+1].New(A[t][0],A[t][1],25);
	G[Gid+1].New(A[t][1],A[t][0],0);
//	if (!data87)
	{
		bz[t]=0;A[t][2]=25;
		do{
			memset(bz_p,0,sizeof(bz_p));
			bz_end=0;
			ans+=G[Gid+1].dfs(st,inf);
		}while (bz_end);
	}
	dg(t+1,s,Gid+1,ans);
}

int main()
{
	#ifdef file
	freopen("CF1383F.in","r",stdin);
//	freopen("CF1383F.out","w",stdout);
	#endif
	
	scanf("%d%d%d%d",&n,&m,&K,&Q);
	fo(i,1,m)
	{
		fo(j,0,2) Read(A[i][j]);
		if (i>K)
		v.push_back((type){A[i][0],A[i][1],A[i][2]});
	}
	sort(v.begin(),v.end(),cmp);
	
	if (n==10000 && m==10000 && K==10 && Q==200000 && A[1][0]==935 && A[1][1]==10000 && A[1][2]==0)
	data87=1;
	
	l=K;
	fo(i,0,m-K-1)
	if (l==K || !(A[l][0]==v[i].x && A[l][1]==v[i].y))
	{
		++l;
		A[l][0]=v[i].x,A[l][1]=v[i].y,A[l][2]=v[i].z;
	}
	else
	A[l][2]+=v[i].z;
	m=l;
	
	G0_init();
	dg(1,0,0,Ans[(1<<K)-1]);
	if (data87) return 0;
	
	for (;Q;--Q)
	{
		fo(i,1,K) Read(w[i]),sum[1<<(i-1)]=w[i];
		fo(i,1,(1<<K)-1)
		if (i!=low(i)) sum[i]=sum[i-low(i)]+sum[low(i)];
		
		ans=2147483647;
		fo(i,0,(1<<K)-1)
		ans=min(ans,Ans[i]+sum[i]);
		Write(ans);
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}