只要每一次将优先级最高的上面的物品移走,就一定能保证是最优解。
所以我们只要想办法简化这个模拟移物品的过程,看完了题解后,发现可以这么想,我们可以把两个栈头碰头的挨在一起,然后设一个指针代表两个栈的分界线,这样移动物品就变成了移动指针,而每一次移动的步数,就是指针和这个物品之间的距离。
开始的时候这个序列每一位都是1,然后如果删除了物品 i,就将 a[i] = 0,这样移动距离就是区间和了,然后用线段树维护即可。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter printf("\n")
#define space printf(" ")
#define Mem(a) memset(a, 0, sizeof(a))
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const int eps = 1e-;
const int maxn = 1e5 + ;
inline ll read()
{
ll ans = ;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch))
{
ans = ans * + ch - ''; ch = getchar();
}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < ) x = -x, putchar('-');
if(x >= ) write(x / );
putchar(x % + '');
} int n1, n2, N;
ll a[maxn], t[maxn];
int pos[maxn]; int l[maxn << ], r[maxn << ], sum[maxn << ];
void build(int L, int R, int now)
{
l[now] = L; r[now] = R;
if(L == R) {sum[now] = ; return;}
int mid = (L + R) >> ;
build(L, mid, now << );
build(mid + , R, now << | );
sum[now] = sum[now << ] + sum[now << | ];
}
void update(int id, int now)
{
if(l[now] == r[now]) {sum[now] = ; return;}
int mid = (l[now] + r[now]) >> ;
if(id <= mid) update(id, now << );
else update(id, now << | );
sum[now] = sum[now << ] + sum[now << | ];
}
int query(int L, int R, int now)
{
if(l[now] == L && r[now] == R) return sum[now];
int mid = (l[now] + r[now]) >> ;
if(R <= mid) return query(L, R, now << );
else if(L > mid) return query(L, R, now << | );
else return query(L , mid, now << ) + query(mid + , R, now << | );
} ll ans = ; int main()
{
n1 = read(); n2 = read();
N = n1 + n2;
for(int i = n1; i > ; --i) a[i] = read();
for(int i = n1 + ; i <= N; ++i) a[i] = read();
for(int i = ; i <= N; ++i) t[i] = a[i];
sort(t + , t + N + ); //离散化优先级
for(int i = ; i <= N; ++i) a[i] = lower_bound(t + , t + N + , a[i]) - t;
for(int i = ; i <= N; ++i) pos[a[i]] = i; //记录每一个优先级所在位置
build(, N, );
int x = pos[N] > n1 ? n1 + : n1; //指针刚开始可以在n1处,也可以在n2处,需判断
for(int i = N; i > ; --i)
{
if(pos[i] < x) ans += query(pos[i] + , x, );
else if(pos[i] > x) ans += query(x, pos[i] - , );
//一定要有if(pos[i] > x),因为刚开始可能优先级最大的在栈顶,不需移动,否则会RE
x = pos[i]; //移动指针
update(x, );
}
write(ans); enter;
return ;
}