第十三届河南省赛J甜甜圈 (树状数组 )

原题
有个小点:吃甜甜圈不算一个步骤
有题易得,最优的步骤是确定了的:每次就找到最大的值,把其上的所有甜甜圈移动到另一边,然后吃掉最大的
为了加速这个过程,我们考虑将两堆甜甜圈顶部对接
这样,样例中的两组甜甜圈
1 4 5
2 7 3
变成了
5 4 1 || 2 7 3
将7吃掉的过程就变成了把那个竖杠移动到7的前面
5 4 1 2 ||7 3,斜杠变化前后中间隔着1个非零数(2)随后7被吃掉,把7设为0,现在是 5 4 1 2 || 0 3 花费步骤1
接下来要吃5,吃掉后变成0 || 4 1 2 0 3 两个竖杠前后隔着3个非零数(4,1,2),所以花费步骤3
接下来吃4,中间没有非零数, 0 || 0 1 2 0 3花费步骤0
接下来吃3 ,前后间隔两个非零数(1,2),花费步骤2
0 0 1 2 0 || 0
接下来吃2,中间无非0数,花费步骤0
吃1,中间无非0数,花费步骤0
故一共花费步骤6
现在问题就是如何快速求前后两个竖杠中间有多少非0数,可以用树状数组来处理这种前缀和问题

#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
//#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 100005;
PII a[N];
int n, m, ans;
int T[N];

int lowbit(int x) {
    
    
	return -x & x;
}

void add(int x, int d) {
    
    
	if (x > N)
		return;
	T[x] += d;
	add(x + lowbit(x), d);
}

int find(int x) {
    
    
	if (x <= 0)
		return 0;
	return T[x] + find(x - lowbit(x));
}


void solve() {
    
    
	cin >> n >> m;
	for (int i = n; i > 0; i--) {
    
    
		add(i, 1);
		cin >> a[i].x;
		a[i].y = i;
	}
	for (int i = n + 1; i <= n + m; i++) {
    
    
		add(i, 1);
		cin >> a[i].x;
		a[i].y = i;
	}
	a[n + m + 1].y = n;//在第一次找中心时,能正确地找到
	sort(a + 1, a + n + m + 1);
	for (int i = n + m; i >= 1; i--) {
    
    
		int f = a[i + 1].y; //找到当前最大值位置
		int t = a[i].y;//进行一次转移后,上一轮的i变成了中心
		add(t, -1);
		ans += abs(find(t) - find(f));
	}
	cout << ans << endl;

}


signed main() {
    
    
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	solve();

}

猜你喜欢

转载自blog.csdn.net/fdxgcw/article/details/121084731