title
BZOJ 3511
LUOGU 4210
Description
Y国有N座城市,并且有M条双向公路将这些城市连接起来,并且任意两个城市至少有一条路径可以互达。
Y国的国王去世之后,他的两个儿子A和B都想成为新的国王,但他们都想让这个国家更加安定,不会用武力解决问题。
于是他们想将这个国家分成两个小国家A国和B国。现在,A拥有1号城市,B拥有N号城市,其他的城市还尚未确定归属哪边(划分之后的国家内部城市可以不连通)。
由于大家都想让国家变得更好,而某些城市的人民愿意国王的A儿子作为他们的领袖,而某些城市更看好B,而为了交通的便捷,如果划分后的公路连接两个同一个国家的城市,那么更利于城市之间的交流。于是大臣们设计了一种对土地划分的评分机制,具体如下:
- 对于城市i,如果它划分给A国,将得到VA[i]的得分;划分给B国,将得到VB[i]的得分。
- 对于一条公路i,如果它连接两个A国的城市,将得到EA[i]的得分;连接两个B国的城市,将得到EB[i]的得分;否则,这条公路将失去意义,将扣除EC[i]的得分。
现请你找到最优的土地划分,使得这种它的评分最高。
Input
第一行包含两个整数N,M,含义如问题描述所示。
接下来一行N-2个非负整数,表示VA[2..N-1]。
接下来一行N-2个非负整数,表示VB[2..N-1]。
接下来M行,每行五个非负整数描述一条公路:X Y EA[i] EB[i] EC[i],含义如问题描述所示。
Output
输出有且仅有一个整数,表示最高评分。
Sample Input
3 3
8
9
1 2 2 6 2
2 3 8 5 7
1 3 9 4 1
Sample Output
11
【样例说明】
A国仅有1号点,B国有2号和3号点。
评分=VB[2]+EB[2]-EC[1]-EC[3]=9+5-2-1=11。
HINT
【数据说明】
数据点 N M 备注
1-2 <=20 <=200 无
3-4 <=5000 <=10000 VA、VB、EA、EB均为0
5-6 <=5000 <=10000 EC均为0
7-10 <=10000 <=40000 无
保证运算过程中及最终结果不超过32位带符号整数类型的表示范围
analysis
说得再清楚也没有我大 menci 的 \(blog\) 清楚了吧,毕竟这道题堪称最小割模型集大成者(也就是套路到家了,文理分科 2.0 版),就这样了。
code
#include<bits/stdc++.h> using namespace std; const int maxn=1e4+10,maxm=3e5+10,inf=0x3f3f3f3f; char buf[1<<15],*fs,*ft; inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; } template<typename T>inline void read(T &x) { x=0; T f=1, ch=getchar(); while (!isdigit(ch) && ch^'-') ch=getchar(); if (ch=='-') f=-1, ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar(); x*=f; } template<typename T>inline void write(T x) { if (!x) { putchar('0'); return ; } if (x<0) putchar('-'), x=-x; T num=0, ch[20]; while (x) ch[++num]=x%10+48, x/=10; while (num) putchar(ch[num--]); } int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],head[maxn],len=1; inline void add(int x,int y,int z) { ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len; ver[++len]=x,edge[len]=0,Next[len]=head[y],head[y]=len; } int s,t; int dist[maxn]; inline bool bfs() { queue<int>q; memset(dist,0,sizeof(dist)); q.push(s),dist[s]=1; while (!q.empty()) { int x=q.front(); q.pop(); for (int i=head[x]; i; i=Next[i]) { int y=ver[i]; if (edge[i] && !dist[y]) { dist[y]=dist[x]+1; if (y==t) return 1; q.push(y); } } } return 0; } inline int get(int x,int low) { if (x==t) return low; int tmp=low; for (int i=head[x]; i; i=Next[i]) { int y=ver[i]; if (edge[i] && dist[y]==dist[x]+1) { int a=get(y,min(tmp,edge[i])); if (!a) dist[y]=0; edge[i]-=a; edge[i^1]+=a; if (!(tmp-=a)) break; } } return low-tmp; } int a[maxn],b[maxn]; int main() { int n,m; read(n);read(m); a[1]=inf,a[n]=0; b[1]=0,b[n]=inf; s=0,t=n+1; int sum=0; for (int i=2,x; i<n; ++i) read(x),a[i]=x<<1,sum+=a[i]; for (int i=2,x; i<n; ++i) read(x),b[i]=x<<1,sum+=b[i]; for (int i=1,x,y,ea,eb,ec; i<=m; ++i) { read(x),read(y),read(ea),read(eb),read(ec); a[x]+=ea, a[y]+=ea, sum+=ea<<1; b[x]+=eb, b[y]+=eb, sum+=eb<<1; add(x,y,ea+eb+(ec<<1)),add(y,x,ea+eb+(ec<<1)); } for (int i=1; i<=n; ++i) add(s,i,a[i]),add(i,t,b[i]); int ans=0; while (bfs()) ans+=get(s,inf); write((sum-ans)>>1),puts(""); return 0; }