题意:

在二维平面的第一象限有\(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. Azure 门户使用概览

    Azure 门户是管理 Azure 云平台的核心工具,用户可以在其中预配和管理 Azure 资源.本教程将帮助你熟悉Azure管理门户,包括一些关键功能的介绍,并演示了如何通过 Azure 门户创建虚 ...

  2. c/c++的const和static区别

    C语言中的const和static用来修饰变量或者函数,用const修饰表示不可改变,用static修饰表示变量或者函数是静态的,作用域控制在函数内. const定义的常量在超出其作用域之后其空间会被 ...

  3. Java的三大特性之继承

    此处我会分为这几个部分来理解继承是怎么样的: 1.区分封装.继承和多态 2.区分限定词的范围 3.区分隐藏.覆盖.重载 4.继承的理解 5.一道面试题的原型 --------------------- ...

  4. 通过Java代码实现图片的放大和缩小

    本文介绍的例子在Android安卓手机上测试通过. 先看看效果吧.可以看到这个开发好的安卓应用有三个按钮:Zoom In缩小图片,Zoom Out放大图片和Save保存. 初始页面: 可以在左边边框自 ...

  5. 卓越管理的实践技巧(2)成功的委派任务 Setup for Successful Delegation

    Setup for Successful Delegation 前文卓越管理的秘密(Behind Closed Doors)最后一部分提到了总结的13条卓越管理的实践技巧并列出了所有实践技巧名称的索引 ...

  6. Android(java)学习笔记132:eclipse 导入项目是提示:某些项目因位于工作空间目录中而被隐藏。

    导致这个错误的原因是工程重名了: 并不是仅仅指文件夹重名,相信很多人也曾经修改过文件夹的名称,可惜没什么用处,关键是修改工程里面的一个文件! 也就是.project这个文件! 用记事本打开,修改一下& ...

  7. 在axios中使用async await

    最近在做树鱼的项目, 联想到 如果用 async await 怎么处理, export async function Test1() { return new Promise((resolve) =& ...

  8. 记录一次mysql中自定义获取UUID的函数

    循环方式一: DELIMITER :; drop function if exists test.fn_test:; create function test.fn_test() ) begin ) ...

  9. Python语言编写脚本时,对日期控件的处理方式

    对日期控件,日期控件的输入控一般是不能手动输入的:把readonly属性去掉就好 其实很简单,我们不去搞时间日期空间,我们把它当成一个普通的input框处理就好了! 但是,很多此类型input框都是禁 ...

  10. TCP/IP协议头部结构体

    TCP/IP协议头部结构体(转) 网络协议结构体定义 // i386 is little_endian. #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN (1) ...