Bubble Cup 11 - Finals [Online Mirror, Div. 2] A. AI robots(线段树动态开点)

题目链接:http://codeforces.com/contest/1046/problem/A

题目大意:有n个机器人排成一排在一条直线上,第i个机器人在xi,同时它可以看到在[xi-ri,xi+ri]的机器人,它的智商是qi

如果两个机器人可以相互看见对方,同时它们的智商差值小于等于k的话,它们就会发生一次谈话。现在问你这n个机器人会发生几次谈话。

题目思路:首先我们来考虑如何知道两个机器人是否能互相看见。

我们可以先按ri从大到小对机器人进行排序,然后用一个线段树记录第 i 个节点是否有机器人,这样我们就可以通过线段树的区间查询知道,对于第 i 个机器人,它可以看到多少个机器人。

由于我们是动态加入机器人的,同时之前加入的机器人的 r 是要大于等于当前机器人的 r 的,所以当前机器人所能看到的机器人肯定也能看到当前的机器人。

接下来我们再来考虑智商的约束条件,常规做法是线段树再套一个线段树,仍旧是通过区间查询查出合适的机器人,但由于本题的内存只有256MB,树套树的空间接受不了,所以无法用树套树解决。

解决本题有一个关键,就是k<=20,这样每次我们只需要暴力遍历40次即可,由于空间的限制原因,所以我们可以通过线段树动态开点来维护智商为 qi 的机器人所在的位置,由于总的只有1e5个机器人,所以所耗费的空间会比树套树小很多。这样就可以解决这个题了。

具体实现看代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
const int MX = 1e5 + 7;
const int mod = 1e9 + 7;
const int N = 1e9;
const int inf = 0x3f3f3f3f;

int n, k, tot;
int root[MX * 40], ls[MX * 40], rs[MX * 40];
ll sum[MX * 40];
struct node {
	int x, r, q;

	bool operator<(const node &A)const {
		return r > A.r;
	}
} a[MX];
vector<int>h;
int get_id(int x) {
	return lower_bound(h.begin(), h.end(), x) - h.begin() + 1;
}
void update(int p, int l, int r, int &rt) {
	if (!rt) rt = ++tot;
	sum[rt]++;
	if (l == r) return;
	int m = (l + r) >> 1;
	if (p <= m) update(p, l, m, ls[rt]);
	else update(p, m + 1, r, rs[rt]);
}
ll query(int L, int R, int l, int r, int rt) {
	if (!rt) return 0;
	if (L <= l && r <= R) return sum[rt];
	int m = (l + r) >> 1;
	ll res = 0;
	if (L <= m) res += query(L, R, l, m, ls[rt]);
	if (R > m) res += query(L, R, m + 1, r, rs[rt]);
	return res;
}

int main() {
	//FIN;
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++) {
		scanf("%d%d%d", &a[i].x, &a[i].r, &a[i].q);
		h.pb(a[i].q); h.pb(a[i].q - k); h.pb(a[i].q + k);
	}
	sort(a + 1, a + n + 1);
	sort(h.begin(), h.end());
	h.erase(unique(h.begin(), h.end()), h.end());
	ll ans = 0;
	for (int i = 1; i <= n; i++) {
		int st = a[i].q - k, ed = a[i].q + k;
		st = get_id(st); ed = get_id(ed);
		for (int j = st; j <= ed; j++) {
			if (!root[j]) continue;
			int L = max(0, a[i].x - a[i].r), R = min(N, a[i].x + a[i].r);
			ans += query(L, R, 0, N, root[j]);
		}
		a[i].q = get_id(a[i].q);
		update(a[i].x, 0, N, root[a[i].q]);
	}
	cout << ans << endl;
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值