CF1045G 题解

前言

题目传送门!

更好的阅读体验?

和模版稍有不同的 cdq 分治。

思路

cdq 是离线算法,所以我们可以先给 \(x_i\) 离散化一下。

同时,记录下 \((x_i - r_i)\)\((x_i + r_i)\) 离散化后对应的结果,即视野范围。

然后,按视野范围从大到小排序。接着就是 cdq 分治了。


假设已经处理好了 \([l, mid]\)\([mid + 1, r]\) 的区间。

现在来到了 cdq 分治的重点部分:处理在 \([l, mid]\)\([mid + 1, r]\) 两个不同区域的机器人。

我们可以再对两个分治区间的智商从小到大排序。

这样,单独看一个子区间,显然具有单调性(废话,都排好序了),于是就可以用 \(\text{two pointers}\) 来解决了。

实现上有点类似尺取法。对于每个 \(i\)\(mid + 1 \to r\),双指针维护 iq 值可以交流的区间。

对于每一个 \(i\),双指针维护完后,统计区间里有多少个数,位置在 \([x_i - r_i, x_i + r_i]\) 里面即可。

这一点可以用树状数组实现。因此,时间复杂度 \(O(n \log^2 n)\)。正常的 cdq 可以很轻松的通过 \(N = 10^5\)

代码

分治区间对 iq 排序时,使用归并排序,更加迅速。

由于时间瓶颈在 \(\text{two pointers}\) 那一块,所以直接 sort 也可以。

直接 sort 的代码可以看:pb 学长的题解

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
struct Data {int pos, lpos, rpos, iq, R;} a[N], t[N];
int x[N], unq[N];
bool cmp(Data p, Data q) {return p.R > q.R;}
int n, k;
LL ans;

int idx[N]; //树状数组板子
int lowbit(int x) {return x & -x;}
void update(int i, int k) {for (; i <= n; i += lowbit(i)) idx[i] += k;}
int query(int i)
{
	int sum = 0;
	for (; i; i -= lowbit(i)) sum += idx[i];
	return sum;
}
int sum(int i, int j) {return query(j) - query(i - 1);}

void MergeSort(int l, int r) //cdq 分治!
{
	if (l >= r) return;
	int mid = (l + r) >> 1;
	MergeSort(l, mid), MergeSort(mid + 1, r);
	int L = l, R = l - 1; //类似尺取法,利用 k 的有序性不断更新 L 和 R
	for (int i = mid + 1; i <= r; i++)
	{
		while (L <= mid && a[i].iq - a[L].iq > k) update(a[L++].pos, -1);  //过时了就减掉
		while (R < mid && a[R + 1].iq - a[i].iq <= k) update(a[++R].pos, 1); //可以接受就加入
		ans += sum(a[i].lpos, a[i].rpos); //统计视野内可见的机器人个数
	}
	for (int i = L; i <= R; i++) update(a[i].pos, -1); //清空 
	
	int i = l, j = mid + 1; //归并排序
	int cur = 0;
	while (i <= mid && j <= r)
		if (a[i].iq <= a[j].iq) t[++cur] = a[i], i++;
		else t[++cur] = a[j], j++;
	while (i <= mid) t[++cur] = a[i], i++;
	while (j <= r) t[++cur] = a[j], j++;
	for (i = l, j = 1; j <= cur; i++, j++) a[i] = t[j];
}
int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) scanf("%d%d%d", &x[i], &a[i].R, &a[i].iq), unq[i] = x[i];
	sort(unq + 1, unq + n + 1); //离散化ing 
	int m = unique(unq + 1, unq + n + 1) - unq - 1;
	for (int i = 1; i <= n; i++)
	{
		a[i].pos = lower_bound(unq + 1, unq + m + 1, x[i]) - unq;
		a[i].lpos = lower_bound(unq + 1, unq + m + 1, x[i] - a[i].R) - unq;
		a[i].rpos = upper_bound(unq + 1, unq + m + 1, x[i] + a[i].R) - unq - 1;
	}
	sort(a + 1, a + n + 1, cmp);
	MergeSort(1, n);
	printf("%lld", ans);
	return 0;
}

希望能帮助到大家!

posted @ 2022-10-21 20:39  liangbowen  阅读(49)  评论(0编辑  收藏  举报