CF1295E Permutation Separation

纪念一道傻逼题。

排列$p_i$,从中分割2堆,开始移动元素使得左边元素小于右边,移动代价为$a_i$

移动结束后代价变成$1-x$,$x+1-n$。这样代价为$ans_x$答案就是$\sum_{i=0}^{n} ans_x$。假设都在右边。

枚举分割点$i$,$x<=p[i],p[i]一开始在左边,就需要移动代价为a_i$,$x>p[i],p[i]不需要移动,就多余的移动-a_i$

代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
struct node
{
int l, r;
ll minn, lazy;
} tree[N << 2];
void pushup(int pos)
{
tree[pos].minn = min(tree[pos * 2].minn, tree[2 * pos + 1].minn);
}
void addlazy(int pos,ll w)
{
tree[pos].lazy += w;
tree[pos].minn += w;
}
void pushdown(int pos)
{
if (tree[pos].lazy)
{
addlazy(pos<<1,tree[pos].lazy);
addlazy(pos<<1|1,tree[pos].lazy);
tree[pos].lazy=0;
}
}
void build(int pos, int l, int r)
{
tree[pos].l = l;
tree[pos].r = r;
if (l == r)
return;
int mid = (l + r) >> 1;
build(pos <<1, l, mid);
build(pos <<1 |1, mid + 1, r);
}
void update(int pos, int l, int r,ll w)
{
if (l <= tree[pos].l && tree[pos].r <= r)
{
addlazy(pos,w);
return;
}
pushdown(pos);
int mid = (tree[pos].l + tree[pos].r) >> 1;
if (l <= mid)
update(pos<<1, l, r, w);
if (r > mid)
update(pos<<1|1, l, r, w);
pushup(pos);
}
int p[N];
ll a[N];
int n;
ll ans = 1e18;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &p[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
build(1,0,n);
for (int i = 1; i <= n; i++)
update(1, p[i] , n, a[i]);

for (int i = 1; i < n; i++)
{
update(1, p[i] , n, -a[i]);
update(1, 0, p[i]-1, a[i]);

ans = min(ans, tree[1].minn);
}
printf("%lld\n", ans);
}