[CF1295E] Permutation Separation - 線段樹,差分
阿新 • • 發佈:2020-11-25
Description
給定一個長度為 \(n\) 的排列,你可以將它切成兩段 \(A,B\),分別作為兩個集合,對於第 \(i\) 個元素,可以花費 \(a[i]\) 的代價把它移動到對面的集合中。求至少花費多少的代價,才能使得一個集合中的任意元素比另一個集合中的任意元素小。
Solution
列舉初態分界點 \(pos\) 和分界值 \(val\),設此時的答案為 \(f(pos,lim)\),暴力計算的話複雜度為 \(O(n^2)\)。
考慮到 \(f(pos,lim)-f(pos-1,lim)=\sum_{lim < p_{pos}} a_{pos} - \sum_{lim \ge p_{pos}} a_{pos}\)
特別注意,lim
是可以 =0
的。
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 1000005; struct SegmentTree { int a[N],tag[N]; void Pushup(int p) { a[p]=min(a[p*2],a[p*2+1]); } void Put(int p,int val) { a[p]+=val; tag[p]+=val; } void Pushdown(int p) { if(tag[p]) { Put(p*2,tag[p]); Put(p*2+1,tag[p]); tag[p]=0; } } void Modify(int p,int l,int r,int ql,int qr,int val) { if(l>qr||r<ql) return; if(l>=ql&&r<=qr) { Put(p,val); } else { Pushdown(p); Modify(p*2,l,(l+r)/2,ql,qr,val); Modify(p*2+1,(l+r)/2+1,r,ql,qr,val); Pushup(p); } } int Query() { return a[1]; } } seg; int n,a[N],b[N],p[N],f[N]; signed main() { ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) cin>>p[i]; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { // cerr<<"Modify "<<p[i]<<" "<<n<<" "<<a[i]<<endl; seg.Modify(1,0,n,p[i],n,a[i]); } int ans=1e18; for(int i=1;i<n;i++) { seg.Modify(1,0,n,0,p[i]-1,a[i]); seg.Modify(1,0,n,p[i],n,-a[i]); ans=min(ans,seg.Query()); } cout<<ans<<endl; }