P3337

全都串起来了!

在 OI 中更易上手的线性规划对偶 一下。

设每个位置要选 次,要 ,约束是

然后对偶:要 ,约束是

这是啥,这是有 个区间 ,价值 ,可以选任意次;有 个点,限制 ,每个点只能被覆盖至多 次。网络流区间覆盖

可以流。让 的流量表示剩余的覆盖次数, 表示选区间 。连边 ,流量 ,费用 ,流这种边表示 点浪费一次覆盖次数。连边 ,流量不限,费用

现在费用流是 。这个增广次数应该可能是 的。再 primal-dual 原始对偶 一下,复杂度

int n,m,c[maxn];
int s,t,flow,ans;
int head[maxn],tot=1;
struct nd{
	int nxt,to,w,c;
}e[maxn<<2];
void add(int u,int v,int w,int c){
	e[++tot]={head[u],v,w,c};head[u]=tot;
	e[++tot]={head[v],u,0,-c};head[v]=tot;
}
int h[maxn];bool vis[maxn];
void spfa(){
	queue<int> q;
	for(int i=0;i<=t;i++)h[i]=inf,vis[i]=0;
	h[s]=0,vis[s]=1,q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			if(e[i].w&&h[v]>h[u]+e[i].c){
				h[v]=h[u]+e[i].c;
				if(!vis[v])vis[v]=1,q.push(v);
			}
		}
	}
}
int dis[maxn],pre[maxn],id[maxn];
bool dij(){
	priority_queue<pii> q;
	for(int i=0;i<=t;i++)dis[i]=inf,vis[i]=0;
	dis[s]=0;q.push({0,s});
	while(!q.empty()){
		int u=q.top().se;q.pop();
		if(vis[u])continue;vis[u]=1;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to,val=e[i].c+h[u]-h[v];
			if(e[i].w&&dis[v]>dis[u]+val){
				dis[v]=dis[u]+val,pre[v]=u,id[v]=i;
				q.push({-dis[v],v});
			}
		}
	}
	return dis[t]!=inf;
}
void work(){
	n=read();m=read();
	for(int i=1;i<=n;i++)c[i]=read();
	s=0,t=n+2;
	for(int i=0;i<=n;i++){
		int v=abs(c[i]-c[i+1]);
		if(c[i]<c[i+1])add(s,i+1,v,0);
		if(c[i]>c[i+1])add(i+1,t,v,0);
	}
	for(int i=1;i<=n;i++)add(i,i+1,inf,0);
	for(int i=1;i<=m;i++){
		int l=read(),r=read(),d=read();
		add(l,r+1,inf,-d);
	}
	spfa();
	int num=0;
	while(dij()){
		for(int i=0;i<=t;i++)h[i]+=dis[i];
		int mn=inf;
		for(int u=t;u!=s;u=pre[u])mn=min(mn,e[id[u]].w);
		flow+=mn;
		for(int u=t;u!=s;u=pre[u]){
			e[id[u]].w-=mn,e[id[u]^1].w+=mn;
            ans+=e[id[u]].c*mn;
		}
		++num;
	}
	// cout<<flow<<" "<<num<<"\n";
	printf("%lld\n",-ans);
}