题意
在平面上有N条平行于Y轴的线段,每条线段都有一个权值,每次可以找出的Y轴上投影互不重叠的若干线段,求M次后,找出的线段最大权值和为多少。(每条线段只能贡献一次)
数据范围
对于30%的数据,N<=100;M<=2;1<=Y1<Y2<=501;
对于50%的数据,P=1;
对于100%的数据,N<=1000;M<=100;1<=Y1<Y2<=5001;1<=P<=100000;1<=X<=5001。
解法
考虑费用流,找m次可以当做总流量为m,然后首先的暴力方法是对于每条线段,与它互不重叠的线段连边,这样边数是
的,并不能过.
然后这里好像算是一个常见技巧:对数轴建边,注意到由于是在y轴投影上互不重叠,所以x坐标是没有用的.所有的坐标只有
级别,所以我们建出(i,i+1,inf,0)这种边,形成纵坐标轴,然后把原来的线段,流量为1,费用是权值,直接建在轴上,跑最大费用最大流.
考虑这样的正确性,一条线段被选了以后,一条和它不相交的线段不会多增加流量,而一条和它相交的边则会增加流量.所以正确.
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e4+5;
const int inf=0x3f3f3f3f3f3f3f3fll;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,m,s;
struct edge{
int v,p,w,c;
}e[maxn<<2];
int h[maxn],cnt=1;
inline void add(int a,int b,int c,int d){
e[++cnt].p=h[a];
e[cnt].v=b;
e[cnt].w=c;
e[cnt].c=d;
h[a]=cnt;
}
int cost,dis[maxn],vis[maxn],ht[maxn],t;
bool bfs(){
//printf("%d\n",s);
queue<int> q;
while(!q.empty())q.pop();
memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis));
q.push(s);
dis[s]=0;int st=dis[t];
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
//printf("%d\n",u);
for(int i=h[u];i;i=e[i].p){
int v=e[i].v;
//printf("%d %d\n",u,v);
if(e[i].w&&dis[v]<dis[u]+e[i].c){
dis[v]=dis[u]+e[i].c;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return dis[t]!=st;
}
int dfs(int u,int rest){
if(rest==0)return rest;
if(u==t){vis[u]=1;return rest;}
vis[u]=1;
int tot=0;
for(int &i=ht[u];i;i=e[i].p){
int v=e[i].v;
if(e[i].w&&(!vis[v])&&dis[v]==dis[u]+e[i].c){
int di=dfs(v,min(rest,e[i].w));
e[i].w-=di;e[i^1].w+=di;
rest-=di;tot+=di;cost+=di*e[i].c;
if(rest==0)break;
}
}
return tot;
}
void dinic(){
while(bfs()){
vis[t]=1;
for(int i=1;i<=s;i++)ht[i]=h[i];
while(vis[t]){
memset(vis,0,sizeof(vis));
dfs(s,inf);
}
}
}
signed main(){
// freopen("3.in","r",stdin);
// freopen("3.out","w",stdout);
n=read(),m=read();s=5e3+6;t=5e3+5;
add(s,1,m,0);add(1,s,0,0);
for(int i=1;i<=n;i++){
int x=read(),y1=read(),y2=read(),p=read();
if(y1>y2)swap(y1,y2);
add(y1,y2,1,p);add(y2,y1,0,-p);
}
//printf("%d\n",s);
for(int i=1;i<5e3+5;i++){
add(i,i+1,inf,0);
add(i+1,i,0,0);
}
//printf("%d\n",s);
dinic();
printf("%lld\n",cost);
return 0;
}