P4694 [PA2013] Raper
P4694 [PA2013] Raper
题目描述
你需要生产
你知道每天 A、B 工厂分别加工一张光盘的花费。你现在有
求生产出
输入格式
第一行包含两个整数
第二行包含
第三行包含
提示
保证
Solution:
拿到题目第一眼:这不费用流秒了?
看完数据范围:被秒的是我
费用流的做法很简单:
st | ed | w | flow | |
---|---|---|---|---|
S | i | 0 | k | |
i | i+1 | 0 | inf | |
i' | i'+1 | 0 | inf | |
i | i' | a[i] | 1 | |
i' | T | b[i] | 1 |
正解:线段树模拟费用流
我们先思考一下 a,b 操作是不是很像 () 我们将 a 当做 ( , b 当做 ). 那么我们最终的答案会是一个匹配的括号序列。那么我们添加括号的方式就有两种:..(...).. 和 ..)...(..
对于():
我们显然可以在任意合法的a,b对上添加()
但是对于 )( :
我们设 a = ( = 1 ,b = ) = -1 缀和数组
假设我们要将 a,b 分别放在 L,R 我们需要保证前 在区间
但是我们发现维护区间最小值是否大于0貌似有点不好整(题解说的),所以我们只需在两个区间合并时判断两个区间的最小值的大小关系然后合并就好了
具体细节见代码
Code:
#include<bits/stdc++.h> #define int long long const int N=5e5+5; const int inf=1e9; using namespace std; int n,m; int a[N],b[N]; long long ans; struct Node{ int x,y; }; inline bool operator <(Node x,Node y) { return a[x.x]+b[x.y] < a[y.x]+b[y.y]; } struct Tree{ int ma,mb,la,lb,mn,tag; Node va,vb,vc; }; Tree _new(int pos) { return Tree{pos,pos,pos,0,0,0,Node{pos,pos},Node{0,0},Node{pos,pos}}; } inline Tree operator +(Tree x,Tree y) { Tree z=_new(0); z.ma= a[x.ma] < a[y.ma] ? x.ma : y.ma; z.mb= b[x.mb] < b[y.mb] ? x.mb : y.mb; z.mn= min(x.mn,y.mn); z.va= min(Node{x.ma,y.mb},min(x.va,y.va)); z.vb= min(x.vb,y.vb); z.vc= min(Node{y.ma,x.mb},min(x.vc,y.vc)); if(x.mn<y.mn) { z.vb=min(z.vb,min(Node{y.ma,x.lb},y.vc)); z.la=x.la; z.lb=(b[x.lb] < b[y.mb] ? x.lb :y.mb); //co<<"case 2: "; } if(x.mn>y.mn) { z.vb=min(z.vb,min(Node{y.la,x.mb},x.vc)); z.la=(a[x.ma] < a[y.la] ? x.ma : y.la); z.lb=y.lb; //co<<"case 1: "; } if(x.mn==y.mn) { z.vb=min(z.vb,Node{y.la,x.lb}); z.la=x.la; z.lb=y.lb; //co<<"case 3: "; } //co<<"push:"<<z.mn<<" "<<z.ma<<" "<<z.mb<<"--"<<z.la<<" "<<z.lb<<"|"<<z.va.x<<"="<<z.va.y<<" "<<z.vb.x<<"="<<z.vb.y<<" "<<z.vc.x<<"="<<z.vc.y<<"\n"; return z; }; struct Segment_Tree{ Tree t[N<<2]; #define ls x<<1 #define rs x<<1|1 inline void add(int x,int k) { t[x].tag+=k,t[x].mn+=k; } void pushup(int x) { t[x]=t[ls]+t[rs]; } void pushdown(int x) { if(!t[x].tag)return; add(ls,t[x].tag);add(rs,t[x].tag); t[x].tag=0; } void build(int x,int l,int r) { if(l==r) { t[x]=_new(l); return; } int mid=l+r>>1; build(ls,l,mid);build(rs,mid+1,r); pushup(x); } void push(int x,int l,int r,int pos) { if(l==r)return ; pushdown(x); int mid=l+r>>1; if(pos<=mid)push(ls,l,mid,pos); if(mid<pos)push(rs,mid+1,r,pos); pushup(x); } void upd(int x,int l,int r,int L,int R,int k) { if(R<l||r<L)return ; if(L<=l&&r<=R) { add(x,k); return ; } int mid=l+r>>1; if(L<=mid)upd(ls,l,mid,L,R,k); if(mid<R)upd(rs,mid+1,r,L,R,k); pushup(x); } #undef ls #undef rs }T; #define rt T.t[1] void work() { cin>>n>>m; for(int i=1;i<=n;i++)scanf("%lld",&a[i]); for(int i=1;i<=n;i++)scanf("%lld",&b[i]); a[0]=b[0]=inf; T.build(1,0,n); for(int i=1;i<=m;i++) { int k; Node u; if(rt.va<rt.vb){u=rt.va,k=1;} else {u=rt.vb,k=-1;} ans+= a[u.x]+b[u.y]; a[u.x]=b[u.y]=inf; //co<<u.x<<" "<<u.y<<"\n"; T.push(1,0,n,u.x);T.push(1,0,n,u.y); T.upd(1,0,n,min(u.x,u.y),max(u.x,u.y)-1,k); } printf("%lld",ans); } #undef rt #undef int int main() { //freopen("P4694.in","r",stdin);freopen("P4694.out","w",stdout); work(); return 0; }