解析
本题的建模方法有很多,我的做法是补集思想转化成志愿者招募然后按照那道题的做法直接做,看题解更多是采用的对于不冲突的线段首尾加边的做法。
在前一道最长k可重区间问题中这两种做法谈不上孰优孰劣,但本题中题解的做法在处理垂直线段时更加简单。
做法和上一题似乎很像,区别一是权值定义有变,二就是关键的垂直线段处理了。
按照题解的做法,直接特判讨论即可。
如果按照志愿者招募呢?
注意到,一条 x=cx=cx=c 的垂直线段和 (l,c),(c,r)(l,c),(c,r)(l,c),(c,r) 都是不冲突的。
考虑如何表示。
对于不垂直的线段 (l,r)(l,r)(l,r),将其改为 (2l+1,2r)(2l+1,2r)(2l+1,2r)。
对于垂直线段 x=cx=cx=c 将其改为 (2c,2c+1)(2c,2c+1)(2c,2c+1)。
这样,在不破坏原来冲突性质的前提下,很好的实现我们的要求。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=3e5+100;
const int M=1e6+100;
const int inf=1e9;int n,m,k;int s,t,tot;
struct node{int to,nxt,cap;int w;
}p[N];
int fi[N],cnt,cur[N];
inline void addline(int x,int y,int c,int w){p[++cnt]=(node){y,fi[x],c,w};fi[x]=cnt;return;
}
inline void add(int x,int y,int c,int w){addline(x,y,c,w);addline(y,x,0,-w);return;
}int dis[N];
int vis[N];
queue<int>q;
bool spfa(){fill(dis,dis+1+tot,inf);dis[s]=0;q.push(s);vis[s]=1;while(!q.empty()){int now=q.front();q.pop();vis[now]=0;for(int i=cur[now]=fi[now];~i;i=p[i].nxt){int to=p[i].to;if(dis[to]<=dis[now]+p[i].w||!p[i].cap) continue;dis[to]=dis[now]+p[i].w;if(!vis[to]) vis[to]=1,q.push(to);}}return dis[t]<inf;
}
int cost;
int flow;
int dfs(int x,int lim){if(vis[x]) return 0;if(x==t||!lim){cost+=lim*dis[t];return lim;}vis[x]=1;int res(0);for(int &i=cur[x];~i;i=p[i].nxt){int to=p[i].to;if(dis[to]!=dis[x]+p[i].w) continue;int add=dfs(to,min(lim,p[i].cap));res+=add;lim-=add;p[i].cap-=add;p[i^1].cap+=add;if(!lim) break;}if(!res) dis[x]=-1;vis[x]=0;return res;
}
void dinic(){flow=cost=0;int tmp(0);while(spfa()){while((tmp=dfs(s,inf))) flow+=tmp;}return;
}
int que[1050],l[1050],r[1050],sum[1050],num;
int val[1050],ans;
signed main(){#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();k=read();for(int i=1;i<=n;i++){int a=read(),b=read(),c=read(),d=read();if(a>c){swap(a,c);swap(b,d);} val[i]=floor(sqrt(1ll*(a-c)*(a-c)+1ll*(b-d)*(b-d)));ans+=val[i];a<<=1;c<<=1;if(a==c) c++;else a++;l[i]=a;r[i]=c;que[++num]=l[i];que[++num]=r[i];}sort(que+1,que+1+num);num=unique(que+1,que+1+num)-que-1;tot=num;s=++tot;t=++tot;add(s,1,inf,0);add(num,t,inf,0);for(int i=1;i<=n;i++){l[i]=lower_bound(que+1,que+1+num,l[i])-que;r[i]=lower_bound(que+1,que+1+num,r[i])-que;sum[l[i]]++;sum[r[i]]--;//printf("(%d %d)\n",l[i],r[i]);add(l[i],r[i],1,val[i]);}for(int i=1;i<num;i++){sum[i]+=sum[i-1];int o=max(sum[i]-k,0);//printf("i=%d sum=%d o=%d\n",i,sum[i],o);add(i,i+1,inf-o,0);}dinic();ans-=cost;printf("%d\n",ans);return 0;
}
/*
4 2
2 0 7 4
5 4 8 6
0 5 8 6
3 1 4 6
*/