HDU 4866 Shooting 扫描线 + 主席树

题意:

在二维平面的第一象限有(n(1 leq n leq 10^5))条平行于(x)轴的线段,接下来有(m)次射击(x \, a \, b \, c)
每次射击会获得一定的分数,假设上一轮的分数为(pre),那么这次射击就会在位置(x)处射击最近的(K=(a cdot pre + b) % c)个靶子。
每射中一个靶子就会获得靶子到(x)轴距离的分数,如果上一轮分数(pre > P),那么本轮分数再乘(2)
输出每次射击所得的分数。

分析:

首先从左到右扫描线段:

  • 遇到线段的左端点,在这个线的位置射穿过去的话,靶的个数增加(1),而且也会比原来得到对应的分数
  • 遇到线段的右端点,在这个线的位置射穿过去的话,靶的个数减少(1),而且也会比原来得到对应的分数

所以(n)条线段就有(2n)个事件,从左往右扫描,维护(2n)棵线段树,对应前(i)个事件发生后对应的靶子的个数以及到(x)轴距离之和。
然后每次计算出(K),接下来就是求树中前(K)小个数字之和,这是主席树的拿手本领。

(x)处射击,要找到对应的那棵线段树,具体来说就是:
位置小于(x)的事件已经发生了,位置等于(x)的左端点事件也发生了,其他的事件都还没发生。
对于位置相同的事件,我们可以把左端点事件排序在右端点事件前面,这样就可以二分查找到对应的线段树。
最后在这棵线段树里查询答案。

(Tips):在计算(K)的过程注意取余,否则可能会溢出。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
const int maxn = 100000 + 10;
const int INF = 0x3f3f3f3f;
const int maxnode = maxn << 5;

struct Event
{
	int pos, sum, type;
	bool operator < (const Event& t) const {
		return pos < t.pos || (pos == t.pos && type < t.type);
	}
};

struct Segment
{
	int l, r, d;
};

Event events[maxn * 2];
Segment a[maxn];
int y[maxn], tot;

int n, m, X;
LL P;

int sz;
int cnt[maxnode], lch[maxnode], rch[maxnode];
LL sum[maxnode];
int root[maxn * 2];

int update(int pre, int L, int R, int pos, LL val, int type) {
	int rt = ++sz;
	lch[rt] = lch[pre];
	rch[rt] = rch[pre];
	cnt[rt] = cnt[pre] + type;
	sum[rt] = sum[pre] + val;
	if(L < R) {
		int M = (L + R) / 2;
		if(pos <= M) lch[rt] = update(lch[pre], L, M, pos, val, type);
		else rch[rt] = update(rch[pre], M+1, R, pos, val, type);
	}
	return rt;
}

LL query(int rt, int L, int R, int k) {
	if(L == R) {
		if(cnt[rt] > k) return sum[rt] / cnt[rt] * k;
		else return sum[rt];
	}
	int M = (L + R) / 2;
	int num = cnt[lch[rt]];
	if(num >= k) return query(lch[rt], L, M, k);
	else return sum[lch[rt]] + query(rch[rt], M+1, R, k - num);
}

int main()
{
	while(scanf("%d%d%d%lld", &n, &m, &X, &P) == 4) {
		for(int i = 0; i < n; i++) {
			scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].d);
			events[i * 2] = (Event){ a[i].l, a[i].d, 1 };
			events[i*2+1] = (Event){ a[i].r + 1, a[i].d, -1 };
			y[i] = a[i].d;
		}
		sort(events, events + n * 2);
		sort(y, y + n);
		tot = unique(y, y + n) - y;

		sz = 0;
		for(int i = 0; i < n * 2; i++) {
			Event& e = events[i];
			int pos = lower_bound(y, y + tot, e.sum) - y + 1;
			root[i + 1] = update(root[i], 1, tot, pos, e.sum * e.type, e.type);
		}

		LL pre = 1;
		while(m--) {
			int x; LL a, b, c;
			scanf("%d%lld%lld%lld", &x, &a, &b, &c);
			int K = (a * pre + b) % c;
			if(!K) { printf("0
"); pre = 0; continue; }
			Event t;
			t = (Event){ x, 0, 2 };
			int rt = lower_bound(events, events + n * 2, t) - events;
			LL ans;
			if(K >= cnt[root[rt]]) ans = sum[root[rt]];
			else ans = query(root[rt], 1, tot, K);
			if(pre > P) ans <<= 1;
			pre = ans;
			printf("%lld
", ans);
		}
	}

	return 0;
}
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5337918.html