P5029

P5029 T'ill It's Over

给定 \(n\) 个 1,用要求的操作使得其中尽可能多的数变成 \(k\)
\(m\) 个不同操作,其中每个操作有限定次数 \(l\)
操作分为四种类型:

  1. 给出 \(a,b\),把一个值为 \(a\) 的数变成 \(b\)
  2. 给出 \(a_1,a_2,b\),把一个值在 \(\left[ a_1,a_2 \right]\) 范围内的数变成 \(b\)
  3. 给出 \(a,b_1,b_2\),把一个值为 \(a\) 的数变成在 \(\left[ b_1,b_2 \right]\) 范围内的一个数。
  4. 给出 \(a_1,a_2,b_1,b_2\),把一个值在 \(\left[ a_1,a_2 \right]\) 范围内的数变成在 \(\left[ b_1,b_2 \right]\) 范围内的一个数。

容易发现,对于每个数的最优决策相同。
因此可以想到网络流,把 \(n\) 作为源点的流量即可。
对于每个在 \(\left[1,k\right]\) 范围内的值建一个点,其中源点连 1,汇点连 \(k\),流量为 \(n\)

看到有区间连边的操作,所以要用到线段树优化建图,把所有操作看成是两个区间的连边,然后线段树加虚点优化建边即可。
线段树的父子节点之间连流量无穷大的边。

一定要注意是在 \(k\) 上开线段树。

点数 \(O(4\times k +m)\),边数 \(O(m \log_2 k)\),因为数据随机,dinic 跑的挺快。

#include <bits/stdc++.h>
#define MI int m=(l+r)>>1;
using namespace std;
const int N=1e6,INF=2e9;
int n,m,k,op,len,ans;

int fir[N<<1],cnt=1;struct E{int v,w,nt;}e[N<<1];
void I(int u,int v,int w=0){e[++cnt]=(E){v,w,fir[u]};fir[u]=cnt;}
void in(int u,int v,int w){I(u,v,w),I(v,u);}

int d[N<<1],cur[N<<1],st,ed;queue <int>q;
bool bfs(){
	for(int i=st;i<=ed;i++)d[i]=0,cur[i]=fir[i];d[st]=1;q.push(st);
	while(!q.empty()){
		int u=q.front(),V;q.pop();
		for(int i=fir[u];i;i=e[i].nt)
			if(!d[V=e[i].v]&&e[i].w)
				d[V]=d[u]+1,q.push(V);
	}return d[ed];
}int dfs(int u,int fl){
	if(u==ed)return fl;int ans=0,V,re;
	for(int i=cur[u];i;i=e[i].nt){
		cur[u]=i;if(d[V=e[i].v]==d[u]+1&&e[i].w){
			re=dfs(V,min(fl,e[i].w));
			e[i].w-=re,e[i^1].w+=re;fl-=re,ans+=re;
			if(!fl)break;
		}
	}if(!ans)d[u]=0;return ans;
}void dinic(){while(bfs())ans+=dfs(st,INF);cout<<ans;}

int ls[N<<1],rs[N<<1],c,r1,r2;
void b1(int &p,int l,int r){
	if(l==r){p=l;return;}p=++c;MI 
	b1(ls[p],l,m);b1(rs[p],m+1,r);
	in(p,ls[p],INF);in(p,rs[p],INF);
}void b2(int &p,int l,int r){
	if(l==r){p=l;return;}p=++c;MI 
	b2(ls[p],l,m);b2(rs[p],m+1,r);
	in(ls[p],p,INF);in(rs[p],p,INF);
}void C(int p,int l,int r,int L,int R,int k,bool f){
	if(l>=L&&r<=R){in(f?p:k,f?k:p,INF);return;}
	MI if(L<=m)C(ls[p],l,m,L,R,k,f);
	if(R>m)C(rs[p],m+1,r,L,R,k,f);
}

int main(){
	cin>>n>>m>>k;c=k;b1(r1,1,k);b2(r2,1,k);
	for(int i=1,a,b,x,y,t1,t2;i<=m;i++){
		cin>>op>>len>>a>>b;t1=++c;t2=++c;
		if(op==1)C(r2,1,k,a,a,t1,1),C(r1,1,k,b,b,t2,0);
		else if(op==2)cin>>x,C(r2,1,k,a,b,t1,1),C(r1,1,k,x,x,t2,0);
		else if(op==3)cin>>x,C(r2,1,k,a,a,t1,1),C(r1,1,k,b,x,t2,0);
		else cin>>x>>y,C(r2,1,k,a,b,t1,1),C(r1,1,k,x,y,t2,0);
		in(t1,t2,len);
	}ed=c+1;in(st,1,n),in(k,ed,n);dinic();return 0;
}
posted @ 2022-05-26 13:20  AIskeleton  阅读(19)  评论(0编辑  收藏  举报