E. Permutation Separationnode
time limit per testios
2 seconds數組
memory limit per testapp
256 megabytesless
inputui
standard inputthis
outputspa
standard outputcode
You are given a permutation p1,p2,…,pnp1,p2,…,pn (an array where each integer from 11 to nn appears exactly once). The weight of the ii-th element of this permutation is aiai.orm
At first, you separate your permutation into two non-empty sets — prefix and suffix. More formally, the first set contains elements p1,p2,…,pkp1,p2,…,pk, the second — pk+1,pk+2,…,pnpk+1,pk+2,…,pn, where 1≤k<n1≤k<n.
After that, you may move elements between sets. The operation you are allowed to do is to choose some element of the first set and move it to the second set, or vice versa (move from the second set to the first). You have to pay aiai dollars to move the element pipi.
Your goal is to make it so that each element of the first set is less than each element of the second set. Note that if one of the sets is empty, this condition is met.
For example, if p=[3,1,2]p=[3,1,2] and a=[7,1,4]a=[7,1,4], then the optimal strategy is: separate pp into two parts [3,1][3,1] and [2][2] and then move the 22-element into first set (it costs 44). And if p=[3,5,1,6,2,4]p=[3,5,1,6,2,4], a=[9,1,9,9,1,9]a=[9,1,9,9,1,9], then the optimal strategy is: separate pp into two parts [3,5,1][3,5,1] and [6,2,4][6,2,4], and then move the 22-element into first set (it costs 11), and 55-element into second set (it also costs 11).
Calculate the minimum number of dollars you have to spend.
Input
The first line contains one integer nn (2≤n≤2⋅1052≤n≤2⋅105) — the length of permutation.
The second line contains nn integers p1,p2,…,pnp1,p2,…,pn (1≤pi≤n1≤pi≤n). It's guaranteed that this sequence contains each element from 11 to nn exactly once.
The third line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤1091≤ai≤109).
Output
Print one integer — the minimum number of dollars you have to spend.
Examples
input
Copy
3 3 1 2 7 1 4
output
Copy
4
input
Copy
4 2 4 1 3 5 9 8 3
output
Copy
3
input
Copy
6 3 5 1 6 2 4 9 1 9 9 1 9
output
Copy
2
給定一個整數n以及一個1~n的全排列,和一個數組a[i]
讓你找一個位置劃開,將排列分紅2個非空的部分,
而後將p[i] 移動到另外一個部分的成本是a[i],
問使左邊的全部數都比右邊的全部的數小須要的最小成本是多少?
在區間\([1,n-1]\)枚舉切割位置i (從p[i] 右邊切開,不取n是由於要保證2部分初始非空) ,時間複雜度\(O(n)\)
那麼咱們知道全部p[i] 位置後面的小於等於 i 的數都要移動到左邊,p[i] 位置即前面的大於 i 的數都要移動到右邊。
咱們尚若能夠\(O(logn)\) 時間內獲得上面移動操做的cost就能夠維護出最小值。
咱們想到了線段樹。
首先對a[i] 作一個前綴和 數組 sum[i] ,表明將1~i的數都移動到右邊須要的cost。
以sum[i] 數組創建區間修改,區間查詢最小值的線段樹。
而後從1到n-1枚舉割切位置i,
對於第i個位置,咱們將找到i在p中的位置 id ,將區間\([1,id-1]\) 減去 a[id],區間\([id,n-1]\) 加上a[id]
意義爲:在切割位置大於等於i 的時候,不須要將數字i移動到右邊部分,又結合線段樹維護的是前綴和數組,
那麼對於每個位置i 用線段樹的根節點維護的最小值去更新答案ans便可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} const int maxn = 300010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int n; int p[maxn]; int id[maxn]; ll a[maxn]; ll sum[maxn]; struct node { int l, r; ll laze; ll val; } segment_tree[maxn << 2]; void pushup(int rt) { segment_tree[rt].val = min(segment_tree[rt << 1].val, segment_tree[rt << 1 | 1].val); } void build(int rt, int l, int r) { segment_tree[rt].l = l; segment_tree[rt].r = r; if (l == r) { segment_tree[rt].val = sum[l]; segment_tree[rt].laze = 0ll; return ; } int mid = (l + r) >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); pushup(rt); } void pushdown(int rt) { segment_tree[rt << 1 | 1].val += segment_tree[rt].laze; segment_tree[rt << 1 | 1].laze += segment_tree[rt].laze; segment_tree[rt << 1 ].val += segment_tree[rt].laze; segment_tree[rt << 1 ].laze += segment_tree[rt].laze; segment_tree[rt].laze = 0; } void update(int rt, int l, int r, int num) { if (segment_tree[rt].laze && l != r) { pushdown(rt); } if (segment_tree[rt].l >= l && segment_tree[rt].r <= r) { segment_tree[rt].val += num; segment_tree[rt].laze += num; return ; } int mid = segment_tree[rt].l + segment_tree[rt].r >> 1; if (r > mid) { update(rt << 1 | 1, l, r, num); } if (l <= mid) { update(rt << 1, l, r, num); } pushup(rt); } int main() { //freopen("D:\\code\\text\\input.txt","r",stdin); //freopen("D:\\code\\text\\output.txt","w",stdout); n = readint(); repd(i, 1, n) { p[i] = readint(); id[p[i]] = i; } repd(i, 1, n) { a[i] = readll(); } repd(i, 1, n) { sum[i] = sum[i - 1] + a[i]; } ll ans = a[n]; build(1, 1, n - 1); ans = min(ans, segment_tree[1].val); int x; repd(i, 1, n) { x = id[i]; if (x != n) { update(1, x, n - 1, -a[x]); } if (x != 1) { update(1, 1, x - 1, a[x]); } ans = min(ans, segment_tree[1].val); } printf("%lld\n", ans ); return 0; }