- 题目:甜甜圈
- 解析:因为每次吃掉的甜甜圈必须是最大甜度的,所以假设第x(1 <= x <= 2)根柱子上的第i个甜甜圈为当前最甜的,那么该根柱子上从顶端到第i-1个甜甜圈都必须转移到另一个柱子上,所以可以通过树状数组对区间进行维护.
- 首先,因为甜甜圈是通过两根柱子顶端进行转移的,为了更好维护甜甜圈的转移过程,我们可以将两根柱子的顶端进行拼接(自行进行想象),然后该位置上有甜甜圈则为1,否则为0,接着将甜甜圈按甜度从大到小排序;
- 我们选第一根或者第二根柱子的顶部位置p作为一个分界点,因为甜甜圈转移方式总是从顶部转移的,取出当前最甜的甜甜圈的位置a[i].pos:
- a[i].pos <= p; 说明该甜甜圈在第一根柱子,那么吃掉该甜甜圈的步数肯定是将(a[i].pos , p]这个区间的甜甜圈给转移,这时候用树状数组维护即可
- a[i].pos < p; 说明该甜甜圈在第二根柱子,那么吃掉该甜甜圈的步数肯定是将第二根柱子顶端到a[i].pos之前的所有甜甜圈转移到第一根柱子上,依然用树状数组维护即可
- 代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int n, m;
int c[N];
long long t = 0;
struct Node
{
int val, pos;
}a[N];
bool cmp(Node a, Node b)
{
return a.val > b.val;
}
int lowbit(int x)
{
return x & (-x);
}
void add(int x, int k)
{
while(x <= n + m)
{
c[x] += k;
x += lowbit(x);
}
}
int query(int x)
{
int res = 0;
while(x)
{
res += c[x];
x -= lowbit(x);
}
return res;
}
int main()
{
cin >> n >> m;
//将第一根柱子上的甜甜圈顶部与第二根柱子上甜甜圈顶部相连
for(int i = n; i >= 1; i--)
{
cin >> a[i].val;
a[i].pos = i;
add(i, 1);
}
for(int i = n + 1; i <= n + m; i++)
{
cin >> a[i].val;
a[i].pos = i;
add(i, 1);
}
sort(a + 1, a + n + m + 1, cmp);
int p = n; //选第一根或者第二根柱子的顶部均可
for(int i = 1; i <= n + m; i++)
{
int pos = a[i].pos; //当前甜度最大的甜甜圈位置
if(pos <= p) //该甜甜圈在第一根柱子
t += query(p) - query(pos);
else t += query(pos) - query(p) - 1; //query(p+1)可能越界
add(pos, -1);
p = pos;
}
cout << t << endl;
return 0;
}