最大费用最大流,建模方法:

黑线、紫线都是流量k,费用0,保障图的连通性,以及只能走k次

红线代表一个给定的区间,流量1代表只能取一次,费用为区间长度代表走过这条区间,可以获得区间长度的价值

跑最大费用最大流(开始时把边权取反,跑最小费用最大流,然后再取反)

需要离散化😂

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
struct edge{
    long long v,w,cost,fail;
    edge(){
    }
    edge(long long a,long long b,long long c,long long d){
        v=a;
        w=b;
        cost=c;
        fail=d;
    }
}e[200100];
long long n,k,s,t,m,incf[200100],pre[200100],vis[200100],dis[200100],head[200100],len,last[200100];
long long Left[200100],Right[200010],u[200100],cnt,U[200100],val[200100];
void add(long long x,long long y,long long z,long long c){
    e[len]=edge(y,z,c,head[x]);
    head[x]=len++;
    e[len]=edge(x,0,-c,head[y]);
    head[y]=len++;
}
bool spfa(){
    queue<long long> q;
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis)); 
    q.push(s);
    dis[s]=0;
    vis[s]=1;
    incf[s]=(long long)1e17;
    while(!q.empty()){
//        cout<<q.front()<<endl;
        long long now=q.front();
        vis[now]=0;
        q.pop();
        for(long long i=head[now];~i;i=e[i].fail){
        //    cout<<i<<endl;
            if(!e[i].w)continue;
            if(dis[e[i].v]>dis[now]+e[i].cost){
                dis[e[i].v]=dis[now]+e[i].cost;
                incf[e[i].v]=min(incf[now],e[i].w);
                pre[e[i].v]=i;
                last[e[i].v]=now;
            //    cout<<"pre of"<<e[i].v<<" is"<<now<<endl;
                if(vis[e[i].v]==0){
                    vis[e[i].v]=1;
                    q.push(e[i].v);
                }
            }
        } 
    }
    //cout<<1<<endl;
    if(dis[t]>=(long long)(1e17))return 0;
    else return 1;
}
long long maxflow=0;
long long ans=0;
long long inf=(long long)1e17;
void update(){
    //cout<<"--------------------------"<<endl;
    long long now=t;
    while(now!=s){
    //    cout<<now<<" "<<last[now]<<endl;
        long long i=pre[now];
        e[i].w-=incf[t];
        e[i^1].w+=incf[t];
        now=last[now];
    } 
    maxflow+=incf[t];
    ans+=dis[t]*incf[t];
    //cout<<ans<<endl;
//    cout<<ans<<endl;
}   
int main(){
    cin>>n>>k;
    memset(head,-1,sizeof(head)); 
    for(int i=1;i<=n;i++){
        cin>>Left[i]>>Right[i];
        u[++cnt]=Left[i];
        u[++cnt]=Right[i];
        val[i]=Right[i]-Left[i];
    }
    sort(u+1,u+cnt+1);
    int cnt1=0;
    for(int i=1;i<=cnt;i++){
        if(u[i]!=u[i-1]){
            U[++cnt1]=u[i];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=cnt1;j++){
            if(Left[i]==U[j])Left[i]=j;
            if(Right[i]==U[j])Right[i]=j;
        }
    }
    long long Max=0;
    for(int i=1;i<=n;i++){
        Max=max(Max,Right[i]);
        add(Left[i],Right[i],1,-val[i]);
    }
    n=Max;
    s=0;
    t=Max+1;
    for(int i=1;i<n;i++){
        add(i,i+1,k,0);
    }
    add(s,1,k,0);
    add(n,t,k,0);
    while(spfa())update();
    cout<<-ans<<endl;
}