【LOJ #3158】「NOI2019」序列(模拟费用流 / 堆)

传送门

考虑一个费用流做法
S → a i ( 1 , a i ) , a i → b i ( 1 , 0 ) , b i → T ( 1 , b i ) , a i → X ( 1 , 0 ) , X → Y ( k − l , 0 ) , Y → b i ( 1 , 0 ) S\rightarrow a_i(1,a_i),a_i\rightarrow b_i(1,0),b_i\rightarrow T(1,b_i),a_i\rightarrow X(1,0),X\rightarrow Y(k-l,0),Y\rightarrow b_i(1,0) Sai(1,ai),aibi(1,0),biT(1,bi),aiX(1,0),XY(kl,0),Ybi(1,0)

考虑利用堆来模拟费用流
x , y x,y x,y间流量为 c n t cnt cnt
考虑每次增加 1 1 1的流量
那么有几种情况
S → a i → b i → T , c n t S\rightarrow a_i\rightarrow b_i\rightarrow T,cnt SaibiT,cnt不变
S → a i → X → Y → b j → T , c n t + 1 S\rightarrow a_i\rightarrow X \rightarrow Y\rightarrow b_j\rightarrow T,cnt+1 SaiXYbjT,cnt+1
S → a i → b i → Y → X → a j → b j → T , c n t − 1 S\rightarrow a_i\rightarrow b_i\rightarrow Y\rightarrow X\rightarrow a_j \rightarrow b_j \rightarrow T,cnt-1 SaibiYXajbjT,cnt1
S → a i → b i → Y → b j , c n t S\rightarrow a_i\rightarrow b_i\rightarrow Y\rightarrow b_j,cnt SaibiYbj,cnt不变
S → a i → X → a j → b j , c n t S\rightarrow a_i\rightarrow X\rightarrow a_j\rightarrow b_j,cnt SaiXajbj,cnt不变

于是用五个堆堆维护 a i + b i , a i , b i ( a i , b i 都 没 被 选 ) a_i+b_i,a_i,b_i(a_i,b_i都没被选) ai+bi,ai,bi(ai,bi) a i , b i ( b i / a i 已 经 被 选 了 的 最 大 值 ) a_i,b_i(b_i/a_i已经被选了的最大值) ai,bi(bi/ai)
即可
复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline ll readll(){
    char ch=gc();
    ll res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	return top;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=200005;
struct node{
	int s,id;
	node(int _a=0,int _b=0):s(_a),id(_b){}
	friend inline bool operator <(cs node &a,cs node &b){
		return a.s<b.s;
	}
};
priority_queue<node>ab,a,b,fa,fb;
int n,k,l,A[N],B[N],va[N],vb[N];
inline void clear(){
	memset(va,0,sizeof(va)),memset(vb,0,sizeof(vb));
	while(a.size())a.pop();
	while(b.size())b.pop();
	while(ab.size())ab.pop();
	while(fa.size())fa.pop();
	while(fb.size())fb.pop();
}
inline void solve(){
	node INF=node(-1e9,0);
	int cnt=0;ll res=0;
	n=read(),k=read(),l=read();
	for(int i=1;i<=n;i++)A[i]=read();
	for(int i=1;i<=n;i++)B[i]=read();
	for(int i=1;i<=n;i++)ab.push(node(A[i]+B[i],i)),a.push(node(A[i],i)),b.push(node(B[i],i));
	for(int i=1;i<=k;i++){
		node v1,v2,v3,v4,v5;
		v1=ab.size()?ab.top():INF;
		v2=a.size()?a.top():INF;
		v3=b.size()?b.top():INF;
		v4=fa.size()?fa.top():INF;
		v5=fb.size()?fb.top():INF;
		if(((cnt==k-l||v1.s>=v2.s+v3.s)&&(v1.s>=v2.s+v5.s&&v1.s>=v3.s+v4.s&&v1.s>=v4.s+v5.s))){
			res+=v1.s,va[v1.id]=vb[v1.id]=1;
		}
		else if(v2.s>v4.s&&v3.s>v5.s&&cnt<k-l){
			res+=v2.s+v3.s,va[v2.id]=vb[v3.id]=1;
			fb.push(node(B[v2.id],v2.id)),fa.push(node(A[v3.id],v3.id));
			cnt++;
		}
		else if(v5.s>v3.s&&v4.s>v2.s){
			res+=v4.s+v5.s,va[v4.id]=vb[v5.id]=1;
			cnt--;
		}
		else if(v4.s+v3.s>v2.s+v5.s){
			res+=v4.s+v3.s,va[v4.id]=vb[v3.id]=1,fa.push(node(A[v3.id],v3.id));
		}
		else {
			res+=v2.s+v5.s,va[v2.id]=vb[v5.id]=1,fb.push(node(B[v2.id],v2.id));
		}
		while(ab.size()&&(va[ab.top().id]||vb[ab.top().id]))ab.pop();
		while(a.size()&&(va[a.top().id]||vb[a.top().id]))a.pop();
		while(b.size()&&(va[b.top().id]||vb[b.top().id]))b.pop();
		while(fa.size()&&(va[fa.top().id]||!vb[fa.top().id]))fa.pop();
		while(fb.size()&&(!va[fb.top().id]||vb[fb.top().id]))fb.pop();
	}
	cout<<res<<'\n';
	clear();
}
int main(){
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	int T=read();
	while(T--)solve();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值