1. 程式人生 > >Finals [Online Mirror, Div. 2] A. AI robots(線段樹動態開點)

Finals [Online Mirror, Div. 2] A. AI robots(線段樹動態開點)

題目大意:有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;
}