HDU 4866 Shooting (主席树)

题目链接  HDU 4866

题意  给定$n$条线段。每条线段平行$x$轴,离x轴的距离为$D$,覆盖的坐标范围为$[L, R]$。

    现在有$m$次射击行动,每一次的射击行动可以描述为在横坐标x处找到离x轴最近的$k$条线段,

    并计算这$k$个目标距离$x$轴的总和。强制在线。

对线段到$x$轴的距离离散化。 以横坐标为下标建立主席树。

应用差分思想,对于每条线段,在$L$处标记$+1$,在R+1处标记$-1$,

查询的时候在横坐标x处则查找横坐标$x$对应的主席树即可。

主席树维护两个东西:

$s[]$表示当前维护的区间范围内的权值和。

$t[]$表示当前维护的区间范围内的权值个数。

对于那点右端点很坐标小于$x$的线段,在之前的两次插入操作中正负抵消。

于是就保证了查询到的线段横坐标范围覆盖了当前的$x$。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

typedef long long LL;

const int M = 4e6 + 10;
const int N = 2e5 + 10;

struct node{
	int pos, val, num;
	friend bool operator < (const node &a, const node &b){
		return a.pos == b.pos ? (a.val == b.val ? a.num < b.num : a.val < b.val) : (a.pos < b.pos);
	}
} c[M], nd;

int ls[M], rs[M], tree[N], val[N], t[M], tot;
int cnt, now, k, x, m, n, et, p;
LL  s[M], pre, ans;

void ins(int l, int r, int vl, int fl, int pre, int &x){
	x = ++tot;
	ls[x] = ls[pre];
	rs[x] = rs[pre];

	s[x] = s[pre] + fl * val[vl];
	t[x] = t[pre] + fl;

	if (l == r) return;

	int mid = (l + r) >> 1;
	if (vl <= mid) ins(l, mid, vl, fl, ls[pre], ls[x]);
	else ins(mid + 1, r, vl, fl, rs[pre], rs[x]);
}

LL query(int id, int l, int r, int k){
	if (l == r) return 1ll * k * val[l];

	int mid = (l + r) >> 1;

	if (t[ls[id]] > k) return query(ls[id], l, mid, k);
	else if (t[ls[id]] == k) return s[ls[id]];
	else return s[ls[id]] + query(rs[id], mid + 1, r, k - t[ls[id]]);
}

int main(){

	while (~scanf("%d%d%d%d", &n, &m, &x, &p)){
		et = 0;
		rep(i, 1, n){
			int l, r, d;
			scanf("%d%d%d", &l, &r, &d);
			val[i] = d;
			++et;
			c[et].pos = l;
			c[et].val = d;
			c[et].num = 1;
			++et;
			c[et].pos = r + 1;
			c[et].val = d;
			c[et].num = -1;
		}

		sort(val + 1, val + n + 1);
		cnt = unique(val + 1, val + n + 1) - val - 1;

		now = 0;

		rep(i, 1, n << 1) c[i].val = lower_bound(val + 1, val + cnt + 1, c[i].val) - val;
		sort(c + 1, c + 2 * n + 1);
		tree[0] = ls[0] = rs[0] = s[0] = t[0] = tot = 0;

		pre = 1;
		now = 0;

		rep(i, 1, 2 * n) ins(1, cnt, c[i].val, c[i].num, tree[i - 1], tree[i]);
		rep(i, 1, m){
			LL pos, a, b, cc;
			scanf("%lld%lld%lld%lld", &pos, &a, &b, &cc);
			k = (a * pre + b) % cc;

			nd.pos = pos;
			nd.val = 1e9;

			int y = upper_bound(c + 1, c + 2 * n + 1, nd) - c - 1;
			ans = query(tree[y], 1, cnt, k);

			if (pre > p) ans *= 2;
			pre = ans;

			printf("%lld\n", ans);
		}

	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/cxhscst2/p/8387690.html

时间: 2024-10-09 04:01:25

HDU 4866 Shooting (主席树)的相关文章

HDU 4866 Shooting 题解:主席树

这题的主要的坑点就是他给你的射击目标有重合的部分,如果你向这些重合的部分射击的话要考虑两种情况: 射击目标数量 ≥ 重合数量 : 全加上 射击目标数量 ≤ 重合数量 : 只加距离*射击目标数量 然而这题的内存还是很良心的,总体比较水吧. 主要做法是按照横坐标1~x建立主席树,每棵主席树维护l,r区间的设计目标数量,以及这些数量如果全部被射击获得的分数,这些在建树的时候是很好维护的. 然后对这些线段的处理要用扫描线的思想,就(左端点)建立一个(+1)的入点,(右端点+1)的位置建立一个(-1)的出

hdu 3727(主席树例题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3727 题意是有4种操作 1.在项链后面插入一个珍珠,保证每一个珍珠都不一样 2.查询第 l 到 第 r 个珍珠之间第k大的珍珠的大小 3.假设把所有珍珠按照大小排序,查询size为x的珍珠的排名 4.查询所有珍珠里第k大的珍珠的大小 题目只需要输出2,3,4询问的所有答案即可 第3个询问很简单,不谈.第4个询问本质上和上一道CWOJ的题是一样的.而第2个操作需要用到主席树的思想. 代码大致思路 建立

HDU 4866 Shooting

题目链接:戳我 题目大意: 射击游戏,玩家站在 X 轴上面,即坐标是[X, 0], 有 N 个目标,每次可以射击 会击中最近的 K 个目标,目标 是平行于 X 的线段, 有M次射击机会,每次射击的得分 是 这K个目标 与 X轴的距离和,如果上一次的得分超过了 P, 那么这次得分就是翻倍.K = (a × Pre + b) % c,Pre为上次的射击得分.Pre初始为 1 求 每次 射击 的 得分 样例解释: 4 3 5 8  //分别是 N, M, X,P 即 目标的个数,射击的次数, 玩家所在

hdu 6601 (主席树)

传送门 题意: 给你一个长度为\(n\)的序列,有\(q\)个询问,每个询问给你一个区间\([l,r]\),每次询问问你在区间\([l,r]\)中,能够组成的最大的三角形的周长. 分析: 因为三角形具有两边之和大于第三边的性质,即\(a+b>c\)的性质.而倘若有若干个数都符合条件,则倘若我们将不等号改成等号,这就形成了一个斐波那契数列.而根据斐波那契数列的性质,值域在\([1,a]\)的斐波那契数列最多会有\(log2(a)\)项. 而在这里可以利用这个性质,每个询问我们贪心的去取第\(k\)

K-th occurrence HDU - 6704 (SA, 主席树)

大意: 给定串$s$, $q$个询问$(l,r,k)$, 求子串$s[l,r]$的第$k$次出现位置. 本来是个简单签到题, 可惜比赛的时候还没学$SA$...... 好亏啊 相同的子串在$SA$中是一定是连续的一段$[L,R]$ 满足对于$L<i\le R$都有$h_i\ge r-l+1$ 可以先用线段树二分出$L,R$, 然后主席树查询第$k$大即可 #include <iostream> #include <algorithm> #include <cstdio&

HDU 4866 Shooting(持久化线段树)

view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; typedef long long ll; #define lson l,m,ls[rt] #define rson m+1,r,rs[r

HDU 4866 多校1 主席树+扫描线

终于是解决了这个题目了 不过不知道下一次碰到主席树到底做不做的出来,这个东西稍微难一点就不一定能做得出 离散化+扫描线式的建树,所以对于某个坐标二分找到对应的那颗主席树,即搜索出结果即可(因为是扫描线式的建树,找到对应的树之后,就知道该点上面的线段有多少条了) 其他就是普通主席树的操作了 主席树里面维护两个东西,一个就是普通的那种在该区间的节点数目,另外就是权值 #include <iostream> #include <cstdio> #include <cstring&g

HDU 4866:Shooting

HDU 4866:Shooting 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4866 题目大意:给出$n$条平行于$x$轴的线段,每次查询给出一个横坐标,求该位置上方的前$k$($k$随询问变化)个线段的高度之和. 主席树 代码如下: 1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 #define MAX 200005 5 using n

hdu 4605 Magic Ball Game (在线主席树/离线树状数组)

hdu 4605 题意: 有一颗树,根节点为1,每一个节点要么有两个子节点,要么没有,每个节点都有一个权值wi .然后,有一个球,附带值x . 球到达某个节点上,如果x==wi,那么球停在这个节点上 .当然,这个点是叶子节点也会停止 . 如果x<wi,那么有1/2的概率走向左子树,有1/2的概率走向右子树 . 如果x>wi,那么有1/8的概率走向左子树,有7/8的概率走向右子树 . 问球经过v节点的概率 .(停在v节点也算) 解法: 在线的话每一个节点建一棵根节点到该节点的线段树,离线的话就先