题目大意
给你n个区间(ai,bi),对应区间的权重为ci。现在让你挑选一些区间,使得任一点出现的次数不超过k,问你满足条件的方案的最大权重和为多少?
分析
离散化后两个端点连边,流量为1,费用为负的权值(因为求的是最大费用最大流),然后再加上源点连一条到1的流量为k,费用为零的边和n到汇点一条到1的流量为k,费用为零的边。
重要的是:i和i+1之间的连边,流量为k,费用为0,因为有的端点之间你要让它们产生联系并且受制与k次。
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>;
using namespace std;
struct arr{
int x,y,w,c,next;
}edge[200000];
int ls[1000];
int dis[1000];
int f[200000];
int v[1000];
int sign[1000];
int edge_m;
int ans;
int s,t;
int n,m;
int add(int x,int y,int w,int c)
{
edge_m++;
edge[edge_m]=(arr){x,y,w,c,ls[x]},f[edge_m]=w,ls[x]=edge_m;
edge_m++;
edge[edge_m]=(arr){y,x,w,-c,ls[y]},f[edge_m]=0,ls[y]=edge_m;
}
bool bfs()
{
for (int i=s;i<=t+1;i++) dis[i]=2000000000;
memset(v,0,sizeof(v));
queue<int> q;
dis[s]=0;
v[s]=0;
q.push(s);
do
{
int x=q.front();
q.pop();
for (int i=ls[x];i;i=edge[i].next)
{
if ((dis[edge[i].y]>dis[x]+edge[i].c)&&(f[i]))
{
dis[edge[i].y]=dis[x]+edge[i].c;
sign[edge[i].y]=i;
if (!v[edge[i].y])
{
v[edge[i].y]=1;
q.push(edge[i].y);
}
}
}
v[x]=0;
}while (!q.empty());
if (dis[t]!=2000000000)
return true;
else
return false;
}
void mcf()
{
int mn=2000000000;
int x=t;
while (sign[x])
{
mn=min(mn,f[sign[x]]);
x=edge[sign[x]].x;
}
ans+=mn*dis[t];
x=t;
while (sign[x])
{
f[sign[x]]-=mn;
f[sign[x]^1]+=mn;
x=edge[sign[x]].x;
}
}
int dinic()
{
while (bfs())
{
mcf();
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
edge_m=1;
memset(edge,0,sizeof(edge));
memset(ls,0,sizeof(ls));
memset(f,0,sizeof(f));
memset(sign,0,sizeof(sign));
s=0; t=0;
for (int i=1;i<=n;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
add(x,y,1,-c);
if (y>t)
t=y;
}
for (int i=1;i<t;i++)
add(i,i+1,200000000,0);
add(s,1,m,0);
add(t,t+1,m,0);
t++;
ans=0;
dinic();
printf("%d\n",-ans);
}
return 0;
}