vp的时候就卡在如何求当前区间内,已经被吃掉的甜甜圈有几个。赛后学了学树状数组,我们可以让每个点为1代表当前位置有甜甜圈,然后初始化树状数组c[i],然后在每次选取最大值过程中,更新c[i]单点也就是nowi为-1,然后树状数组可以快速求出当前区间1的个数,就代表需要移动的个数,循环n1 + n2次即可,时间复杂度为nlogn。
#include <bits/stdc++.h>
#define int long long
using namespace std;
#define endl '\n'
typedef long long ll;
const int N = 2e5 + 10;
const int mod = 998244353;
int n,c[N]; //c为树状数组
int a[N]; //存储甜甜圈甜度
map<int,int> mp; //存储甜甜圈位置
priority_queue<int,vector<int>,less<>> q; //存储当前应当吃的甜甜圈,降序排列
int lowbit(int i){ //求c[x]的区间长度
return (-i) & i;
}
void add(int i,int z){ //点更新,a[i]加上z
for (; i <= n ; i += lowbit(i)) { //更新所有后继,祖先
c[i] += z;
}
}
int sum(int i){ //求前缀和,a1+a2+a3
int sum = 0;
for (; i > 0; i -= lowbit(i)) { //累加所有前驱
sum += c[i];
}
return sum;
}
int sum(int i,int j){ //求区间和
return sum(j) - sum(i-1);
}
void solve() {
int n1,n2;
cin>>n1>>n2;
n = n1 + n2;
for (int i = n1; i >= 1; --i) {
cin>>a[i];
add(i,1);
q.push(a[i]);
mp[a[i]] = i;
}
for (int i = 1; i <= n2; ++i) {
cin>>a[n1 + i];
add(i + n1,1);
q.push(a[i + n1]);
mp[a[i + n1]] = n1 + i;
}
int nowx = q.top(); //当前需要的甜度
int nowi = mp[q.top()]; //当前甜度对应数组的位置
int ans = 0; //记录移动次数
int l = n1,r = n1 + 1; //分别为左队列和右队列的队头位置
for (int i = 1; i <= n; ++i) {
nowi = mp[q.top()];
q.pop();
if(nowi == l || nowi == r){
add(nowi,-1);
if(nowi == l){
l = nowi - 1;
} else {
r = nowi + 1;
}
}else if(nowi < l){
ans += sum(l) - sum(nowi); //移动的元素个数,其实就是nowi到l的1的个数
l = nowi - 1;
r = nowi + 1;
add(nowi,-1);
} else{
ans += sum(nowi - 1) - sum(r - 1); //同理
r = nowi + 1;
l = nowi - 1;
add(nowi,-1);
}
}
cout<<ans<<endl;
}
signed main() {
int t = 1;
//cin >> t;
while (t--) {
solve();
}
return 0;
}