Bubble Cup 11 - Finals [Online Mirror, Div. 1] G.AI robots 主席树

Description
有n个机器人,每个机器人有三个参数:xi,ri,qi
定义一个机器人i可以看见另一个机器人j为:
xi - ri <= xj <= xi + ri。
现在可以互相看见,且qi差值不超过k的可以谈话,
求有多少对可以谈话。


Sample Input
3 2
3 6 1
7 3 10
10 5 8


Sample Output
1


我们先考虑有序数对(i,j)满足条件,且xj < xi
那么我们需要满足的条件为:
xj + rj >= xi,xi - ri <= xj <= xi + ri,abs(qi - qj) <= k
对于一个我们可以将它拆成两个询问。
1 ~ xi - ri - 1中满足xj + rj >= xi,abs(qi - qj) <= k的点数以及
1 ~ xi中满足xj + rj >= xi,abs(qi - qj) <= k的点数以及
那么我们便可以将他们变成一个询问,按照x排序。
对于一个j的插入,就相当于在xj的位置插入一个东西,那它就变成一个修改。
然后对于另外两个限制条件,首先是q值,因为k <= 20,我们可以考虑按照q来建树,然后就可以直接查询了。
然而会有xi重复的情况你统计一下去一下重即可。
代码卡了卡常,有点丑


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
inline int _min(int x, int y) {return x < y ? x : y;}
inline int _max(int x, int y) {return x > y ? x : y;}
inline int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

struct tnode {
	int lc, rc, c;
} t[30 * 310000]; int cnt, rt[610000];
struct node {
	int x, l, r, ll, rr, c;
} a[610000], q[610000]; int root[610000];
int tt, xx[610000], rr[610000], Q[610000], v[610000];
int b[610000], pa[610000], hh[610000], pp[610000];
LL ans = 0;

bool cmp(node a, node b) {
	if(a.x == b.x) return a.l < b.l;
	return a.x < b.x;
}

bool cmp1(node a, node b) {
	if(a.x == b.x) return a.c > b.c;
	return a.x < b.x;
}

void Link(int &u, int l, int r, int p, int c) {
	if(!u) u = ++cnt;
	t[u].c++;
	if(l == r) return ;
	int mid = (l + r) / 2;
	if(p <= mid) Link(t[u].lc, l, mid, p, c);
	else Link(t[u].rc, mid + 1, r, p, c);
}

int query(int u1, int l, int r, int ll, int rr) {
	if(l == ll && r == rr) return t[u1].c;
	int mid = (l + r) / 2;
	if(rr <= mid) return query(t[u1].lc, l, mid, ll, rr);
	else if(ll > mid) return query(t[u1].rc, mid + 1, r, ll, rr);
	else return query(t[u1].lc, l, mid, ll, mid) + query(t[u1].rc, mid + 1, r, mid + 1, rr);
}

inline void solve(int l, int r) {
	tt++;
	for(register int i = l; i <= r; ++i) {
		if(v[a[i].c] != tt) v[a[i].c] = tt, root[a[i].c] = 0;
		root[a[i].c]++;
	}
	int sum = 0;
	for(register int i = l; i <= r; ++i)
		for(int j = a[i].ll; j <= a[i].rr; j++) if(pa[j] && v[j] == tt) sum += root[j];
	ans = ans - (sum - (r - l + 1)) / 2 - (r - l + 1);
}

int main() {
	int n, k; scanf("%d%d", &n, &k);
	for(register int i = 1; i <= n; ++i) {
		xx[i] = read(), rr[i] = read(), Q[i] = read();
		b[i * 3 - 2] = _max(0, xx[i] - rr[i]);
		b[i * 3 - 1] = xx[i];
		b[i * 3] = _min(xx[i] + rr[i], 1e9);
	} sort(b + 1, b + 3 * n + 1);
	int ln = 3 * n + 1;
	ln = unique(b + 1, b + ln + 1) - (b + 1);
	for(register int i = 1; i <= n; ++i) {
		a[i].x = lower_bound(b + 1, b + ln, xx[i]) - b;
		a[i].l = lower_bound(b + 1, b + ln, _max(0, xx[i] - rr[i])) - b;
		a[i].r = lower_bound(b + 1, b + ln, _min(xx[i] + rr[i], 1e9)) - b;
	}
	for(register int i = 1; i <= n; ++i) {
		b[i * 3 - 2] = _max(0, Q[i] - k);
		b[i * 3 - 1] = Q[i];
		b[i * 3] = _min(Q[i] + k, 1e9);
	} sort(b + 1, b + 3 * n + 1);
	int op = 3 * n + 1;
	op = unique(b + 1, b + op + 1) - (b + 1);
	for(register int i = 1; i <= n; ++i) {
		a[i].c = lower_bound(b + 1, b + op, Q[i]) - b;
		pa[a[i].c] = 1;
		a[i].ll = lower_bound(b + 1, b + op, _max(0, Q[i] - k)) - b;
		a[i].rr = lower_bound(b + 1, b + op, _min(Q[i] + k, 1e9)) - b;
	} sort(a + 1, a + n + 1, cmp);
	int cnt = 0;
	for(register int i = 1; i <= n; ++i) {
		q[++cnt].x = a[i].l - 1; q[cnt].l = a[i].ll; q[cnt].r = a[i].rr, q[cnt].ll = a[i].x, q[cnt].c = 1;
		q[++cnt].x = a[i].x, q[cnt].l = a[i].ll; q[cnt].r = a[i].rr, q[cnt].ll = a[i].x, q[cnt].c = 2;
		q[++cnt].x = a[i].x, q[cnt].l = a[i].r, q[cnt].r = a[i].c, q[cnt].c = 3;
	} sort(q + 1, q + cnt + 1, cmp1);
	int tp1 = 0, tp2 = 0;
	ans = 0; int last = 0;
	for(register int i = 1; i <= cnt; ++i) {
		if(q[i].c == 3) Link(rt[q[i].r], 1, ln, q[i].l, 1);
		else {
			int tt = 0;
			for(register int j = q[i].l; j <= q[i].r; ++j) {
				if(!pa[j]) continue;
				tt += query(rt[j], 1, ln, q[i].ll, ln);
			} if(q[i].c == 1) ans -= tt;
			else ans += tt;
		}
	}
	int l = 1;
	for(register int i = 1; i <= n; ++i) {
		if(i == 1 || a[i].x == a[i - 1].x) continue;
		else solve(l, i - 1), l = i;
	}
	solve(l, n); printf("%lld\n", ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值