这题的主要的坑点就是他给你的射击目标有重合的部分,如果你向这些重合的部分射击的话要考虑两种情况:

射击目标数量 ≥ 重合数量 : 全加上

射击目标数量 ≤ 重合数量 : 只加距离*射击目标数量

然而这题的内存还是很良心的,总体比较水吧。

主要做法是按照横坐标1~x建立主席树,每棵主席树维护l,r区间的设计目标数量,以及这些数量如果全部被射击获得的分数,这些在建树的时候是很好维护的。

然后对这些线段的处理要用扫描线的思想,就(左端点)建立一个(+1)的入点,(右端点+1)的位置建立一个(-1)的出点,然后从左往右扫一遍即可。

具体过程见代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#define INF 2*0x3f3f3f3f using namespace std; int n, m, x, p; struct N { int ls, rs, w; long long sum; } tree[6000100];
int roots[200010];
int b[200010], tot, cnt; int build_tree(int l, int r) {
int newnode = tot++;
tree[newnode].w = 0;
tree[newnode].sum = 0;
if (l != r) {
int mid = (l + r) / 2;
tree[newnode].ls = build_tree(l, mid);
tree[newnode].rs = build_tree(mid + 1, r);
}
return newnode;
} int updata(int rt, int pos, int val) {
int newnode = tot++, tmp = newnode;
long long add = b[pos - 1];
tree[newnode].sum = tree[rt].sum + add * val;
tree[newnode].w = tree[rt].w + val;
int l = 1, r = cnt;
while (l < r) {
int mid = (l + r) / 2;
if (pos <= mid) {
tree[newnode].ls = tot++;
tree[newnode].rs = tree[rt].rs;
newnode = tree[newnode].ls;
rt = tree[rt].ls;
r = mid;
}
else {
tree[newnode].ls = tree[rt].ls;
tree[newnode].rs = tot++;
newnode = tree[newnode].rs;
rt = tree[rt].rs;
l = mid + 1;
}
tree[newnode].sum = tree[rt].sum + add * val;
tree[newnode].w = tree[rt].w + val;
}
return tmp;
} long long query(int rt, int k) {
//printf("rt = %d k = %d\n",rt,k);
int l = 1, r = cnt;
long long ans = 0;
while (l < r) {
int mid = (l + r) / 2;
int tmp = tree[tree[rt].ls].w;
if (tmp >= k) {
rt = tree[rt].ls;
r = mid;
}
else {
k -= tmp;
ans += tree[tree[rt].ls].sum;
rt = tree[rt].rs;
l = mid + 1;
}
}
if (tree[rt].w != 0)
ans += tree[rt].sum / tree[rt].w * min(k, tree[rt].w);
return ans;
} struct P {
int x, y, val;
P() {}
P(int _x, int _y, int _val) : x(_x), y(_y), val(_val) {}
bool operator < (const P &rhs) const {
return x < rhs.x;
}
} pois[500010]; void print(int rt, int l = 1, int r = cnt) {
printf("l = %d r = %d w = %d sum = %I64d\n", l, r, tree[rt].w, tree[rt].sum);
if (l != r) {
int mid = (l + r) / 2;
print(tree[rt].ls, l, mid);
print(tree[rt].rs, mid + 1, r);
}
} int main() {
//freopen("in.in", "r", stdin);
//freopen("out.out", "w", stdout);
while (scanf("%d %d %d %d", &n, &m, &x, &p) != EOF) {
int l1, l2, d;
int ps = 0;
for (int i = 0; i < n; i++) {
scanf("%d %d %d", &l1, &l2, &d);
b[i] = d;
pois[ps++] = P(l1, d, 1);
pois[ps++] = P(l2 + 1, d, -1);
}
sort(b, b + n);
cnt = unique(b, b + n) - b; sort(pois, pois + ps); tot = 0;
roots[0] = build_tree(1, cnt);
int t = 0;
for (int i = 1; i <= x; i++) {
roots[i] = roots[i - 1];
while (t < ps && pois[t].x == i) {
int tmp = (int)(lower_bound(b, b + cnt, pois[t].y) - b) + 1;
roots[i] = updata(roots[i], tmp, pois[t].val);
t++;
}
}
/*
for (int i = 1; i <= x; i++) {
printf("**********************tree %d is : \n", i);
print(roots[i]);
}
*/ long long now = 1;
int xs, as, bs, cs;
for (int i = 0; i < m; i++) {
//printf("i = %d\n", i);
scanf("%d %d %d %d", &xs, &as, &bs, &cs);
long long tmp = query(roots[xs], (now * as + bs) % cs);
if (now > p) tmp *= 2;
printf("%I64d\n", tmp);
now = tmp;
}
}
return 0;
}

HDU 4866 Shooting 题解:主席树的更多相关文章

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

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

  2. HDU 4866 Shooting (主席树)

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

  3. HDU 4866 Shooting 扫描线 + 主席树

    题意: 在二维平面的第一象限有\(n(1 \leq n \leq 10^5)\)条平行于\(x\)轴的线段,接下来有\(m\)次射击\(x \, a \, b \, c\). 每次射击会获得一定的分数 ...

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

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

  5. HDU 5919 Sequence II 主席树

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

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

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

  7. hdu 2665 Kth number 主席树

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

  8. HDU 4417 Super Mario 主席树

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

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

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

随机推荐

  1. 微信JS-SDK接口上传图片以及wx.config的配置

    最近做的微信网页要实现一个上传图片的功能,倒腾了半天终于搞好了,具体的步骤可以查看微信官方文档https://developers.weixin.qq.com/doc/offiaccount/OA_W ...

  2. PHPCMS如何修改网站名称,网站关键词,网站描述

    首先需要登录网站后台,填写管理员用户名密码之后,点击登 点击phpcms后台顶部的"设置"按钮,如下图所示. 然后点击"相关设置"下的"站点管理&qu ...

  3. (54) C# 调用 kernel32.dll

    https://www.cnblogs.com/cwy173/archive/2010/10/02/1841321.html Kernel32 API AddAtom 向本地原子表添加一个字符串 Al ...

  4. JS-日期和时间

    # 格式化日期和时间 扩展 Date: Date.prototype.format = function(format){ var o = { "M+" : this.getMon ...

  5. main()和代码块

    main方法 * main()方法的使用说明 * main方法是程序的主入口(一个主程序 先从main开始进行执行) * * * main方法也可以是一个普通的静态方法 代码块 代码块也是类的成员变量 ...

  6. SQLSERVER 时间日期函数,查询今天日期、昨天、一个星期、半年前的数据

    今天的所有数据:select * from 表名 where DateDiff(dd,datetime类型字段,getdate())=0昨天的所有数据:select * from 表名 where D ...

  7. .NET Core开源组件:后台任务利器之Hangfire 转载 https://www.cnblogs.com/chenug/p/6655636.html

    .NET Core开源组件:后台任务利器之Hangfire   一.简述 Hangfire作为一款高人气且容易上手的分布式后台执行服务,支持多种数据库.在.net core的环境中,由Core自带的D ...

  8. python学习笔记:循环语句——while、for

    python中有两种循环,while和for,两种循环的区别是,while循环之前,先判断一次,如果满足条件的话,再循环,for循环的时候必须有一个可迭代的对象,才能循环,比如说得有一个数组.循环里面 ...

  9. 使用element-ui 组件动态合并table的行/列(第二次修改)

    这是第二次修改,在通过调用后台接口返回来的时候,发现了代码中的问题:现在将博客中错误的地方改过来,添加备注 文章需求:动态实现table表格中行/列的自动合并 使用框架及UI类库:Vue+Elemen ...

  10. css中的居中问题

    前两天写了一篇关于display:table的用法,里面涉及到居中的问题,这两天愈发觉得css中的居中是一个值得关注的问题,现总结如下. 一.垂直居中 (1)inline或者inline-*元素 1. ...