题意:

在二维平面的第一象限有\(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\n"); 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\n", ans);
}
} return 0;
}

HDU 4866 Shooting 扫描线 + 主席树的更多相关文章

  1. HDU 4866 Shooting (主席树)

    题目链接  HDU 4866 题意  给定$n$条线段.每条线段平行$x$轴,离x轴的距离为$D$,覆盖的坐标范围为$[L, R]$.   现在有$m$次射击行动,每一次的射击行动可以描述为在横坐标$ ...

  2. HDU 4866 Shooting(主席树)题解

    题意:在一个射击游戏里面,游戏者可以选择地面上[1,X]的一个点射击,并且可以在这个点垂直向上射击最近的K个目标,每个目标有一个价值,价值等于它到地面的距离.游戏中有N个目标,每个目标从L覆盖到R,距 ...

  3. HDU 4866 Shooting(持久化线段树)

    view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...

  4. HDU 4866 Shooting 题解:主席树

    这题的主要的坑点就是他给你的射击目标有重合的部分,如果你向这些重合的部分射击的话要考虑两种情况: 射击目标数量 ≥ 重合数量 : 全加上 射击目标数量 ≤ 重合数量 : 只加距离*射击目标数量 然而这 ...

  5. hdu 2665 Kth number 主席树

    Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Prob ...

  6. HDU 5919 Sequence II 主席树

    Sequence II Problem Description   Mr. Frog has an integer sequence of length n, which can be denoted ...

  7. HDU 4417 Super Mario 主席树

    分析:找一个区间里小于等于h的数量,然后这个题先离散化一下,很简单 然后我写这个题主要是熟悉一下主席树,其实这个题完全可以离线做,很简单 但是学了主席树以后,我发现,在线做,一样简单,而且不需要思考 ...

  8. hdu 5919--Sequence II(主席树--求区间不同数个数+区间第k大)

    题目链接 Problem Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2 ...

  9. HDU - 2665 Kth number 主席树/可持久化权值线段树

    题意 给一个数列,一些询问,问$[l,r]$中第$K$大的元素是哪一个 题解: 写法很多,主席树是最常用的一种之一 除此之外有:划分树,莫队分块,平衡树等 主席树的定义其实挺模糊, 一般认为就是可持久 ...

随机推荐

  1. This file's format is not supported or you don't specify a correct format. 解决办法

    string path = @"c:\请假统计表.xlsx"; Workbook workBook = new Workbook(); workBook.Open(path); A ...

  2. 洛谷P1965 转圈游戏

    https://www.luogu.org/problem/show?pid=1965 快速幂 #include<iostream> #include<cstdio> #inc ...

  3. 记录:swift学习笔记1-2

    swift还在不断的更新做细微的调整,都说早起的鸟儿有虫吃,那么我们早点出发吧,趁着国内绝大多数的coder们还没有开始大范围普遍应用. 网上有些大神说:swift很简单!我不同意这个观点,假如你用h ...

  4. js基础的自定义属性练习

    js基础的自定义属性练习: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type ...

  5. JavaScript笔记6-数组新方法

    七.ECMAScript5关于数组的新方法 1.forEach():遍历数组,并为每个元素调用传入的函数;     举例:    var a = [1,2,3]; var sum = 0; //传一个 ...

  6. js使用my97插件显示当前时间,且select控制计算时间差

    做页面需要两个时间输入框一个显示当前时间,一个显示之前的时间,并且需要一个select下拉框控制两个时间输入框之间的差,效果如下图: 这里使用的是My97DatePicer,简单方便,引入my97插件 ...

  7. BZOJ 4881: [Lydsy2017年5月月赛]线段游戏

    4881: [Lydsy2017年5月月赛]线段游戏 Time Limit: 3 Sec  Memory Limit: 256 MBSubmit: 164  Solved: 81[Submit][St ...

  8. Linux 的数字权限意义

    三个组 每个都有三个权限 r w x每个权限用二进制 0 和 1 标示 1即为有此权限 0 标示无权限  ower    group  other  r w x    r w x  r w x 每个组 ...

  9. GIT分布式版本控制器的前后今生

    Git的入门与安装 GIT基础操作 GIT的分支应用 GITLAB应用 gitlab与pycharm应用 GITHUB使用

  10. stixel 理解

    在车辆所处平面建立极坐标占位网格(polar occupancy grid),将视差图所代表的三维世界(3D world) 正交投影到该平面中. occupancy:每个网格被赋予一个占位数,代表了该 ...