原始对偶费用流

\(Dijkstra\) 代替 \(SPFA\)Link,但是这篇博客的代码上来就跑 \(Dijkstra\),复杂度可能会被卡成指数。

\(\text{Problem}:\)Interval Graph

\(\text{Solution}:\)

满足题意的充要条件:每个点至多被两个区间覆盖。

\(i\rightarrow i+1\) 连一条流量为 \(2\),费用为 \(0\) 的边。

\(l\rightarrow r+1\) 连一条流量为 \(1\),费用为 \(-w\) 的边。

然后跑最小费用最大流。此题需要用 \(Primal-dual\) 优化。

但是第一次跑 \(Dijkstra\) 的时候有负权,所以先把边权都变成正的,再跑 \(Dijkstra\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
using namespace std; const int N=500010, INF=1e18;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,Ans;
struct Link { int x,y,z; }g[N];
int S,T,dis[N],pre[N],H[N],book[N];
int head[N],maxE,cur[N]; struct Edge { int nxt,to,rdis,cost; }e[N<<2];
inline void Add(int u,int v,int w1,int w2)
{
	e[maxE].nxt=head[u];
	head[u]=maxE;
	e[maxE].to=v;
	e[maxE].rdis=w1;
	e[maxE].cost=w2;
	maxE++;
}
struct Node { int x,w; inline bool operator < (const Node& a) const { return w>a.w; } };
inline bool Dijk()
{
	priority_queue<Node> Q;
	memset(dis,0x3f,sizeof(dis));
	memset(book,0,sizeof(book));
	memset(pre,-1,sizeof(pre));
	dis[S]=0, Q.push((Node){S,0});
	while(!Q.empty())
	{
		Node now=Q.top(); Q.pop();
		int x=now.x;
		if(book[x]) continue;
		book[x]=1;
		for(ri int i=head[x];~i;i=e[i].nxt)
		{
			int v=e[i].to;
			if(e[i].rdis>0&&dis[v]>dis[x]+e[i].cost+H[x]-H[v])
			{
				dis[v]=dis[x]+e[i].cost+H[x]-H[v];
				pre[v]=i;
				Q.push((Node){v,dis[v]});
			}
		}
	}
	return ~pre[T];
}
signed main()
{
	memset(head,-1,sizeof(head));
	n=read();
	for(ri int i=1;i<=n;i++)
	{
		int x,y,z;
		x=read(), y=read(), z=read();
		T=max(T,y+1);
		g[i]=(Link){x,y,z};
	}
	for(ri int i=0;i<T;i++) Add(i,i+1,2,0), Add(i+1,i,0,0);
	for(ri int i=1;i<=n;i++) Add(g[i].x,g[i].y+1,1,-g[i].z), Add(g[i].y+1,g[i].x,0,g[i].z);
	memset(pre,-1,sizeof(pre));
	memset(dis,0x3f,sizeof(dis));
	dis[S]=0;
	for(ri int x=0;x<=T;x++)
	for(ri int i=head[x];~i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(e[i].rdis>0&&dis[v]>dis[x]+e[i].cost)
			dis[v]=dis[x]+e[i].cost, pre[v]=i;
	}
	if(pre[T]==-1) return puts("0")&0;
	for(ri int i=0;i<=T;i++) if(dis[i]<INF) H[i]+=dis[i];
	int res=INF;
	for(ri int i=T;i!=S;i=e[pre[i]^1].to) res=min(res,e[pre[i]].rdis);
	for(ri int i=T;i!=S;i=e[pre[i]^1].to)
	{
		e[pre[i]].rdis-=res;
		e[pre[i]^1].rdis+=res;
	}
	Ans+=res*H[T];
	while(Dijk())
	{
		for(ri int i=0;i<=T;i++) if(dis[i]<INF) H[i]+=dis[i];
		int res=INF;
		for(ri int i=T;i!=S;i=e[pre[i]^1].to) res=min(res,e[pre[i]].rdis);
		for(ri int i=T;i!=S;i=e[pre[i]^1].to)
		{
			e[pre[i]].rdis-=res;
			e[pre[i]^1].rdis+=res;
		}
		Ans+=res*H[T];
	}
	printf("%lld\n",-Ans);
	return 0;
}
posted @ 2021-02-28 16:19  zkdxl  阅读(233)  评论(0编辑  收藏  举报