[LOJ#2255][BZOJ5017][Snoi2017]炸弹

试题描述

在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: 
Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 
现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? 

输入

第一行,一个数字 N,表示炸弹个数。 
第 2∼N+1行,每行 2 个数字,表示 Xi,Ri,保证 Xi 严格递增。 
N≤500000
−10^18≤Xi≤10^18
0≤Ri≤2×10^18

输出

一个数字,表示Sigma(i*炸弹i能引爆的炸弹个数),1<=i<=N mod10^9+7。

输入示例


输出示例


数据规模及约定

见“输入

题解

显然一个炸弹能引爆的范围一定是一段连续的区间,于是我们就考虑求它的左右端点。

考虑一种容易漏掉的情况:一个炸弹 a 引爆左边一个炸弹 b,b 引爆 a 右侧的 c,c 引爆 b 左侧的 d……这种情况我们不难发现从 a 到 d,炸弹的爆炸半径一定倍增(比如若 b 的半径小于 a 半径的两倍,由于 b 可以引爆 a 右边的 c,所以 a 可以直接引爆 c,不需要借助 b)。

剩下的情况就是连锁爆炸(即爆炸只往一个方向传递),处理这个东西我们只需要用单调栈正反扫一遍处理出每个炸弹向左向右连锁爆炸能炸到的最远的炸弹就可以了(不妨设向左向右最远的炸弹编号分别为 lft[i] 和 rgt[i])。

最后我们用 RMQ 维护一下 lft[i] 的最小值,rgt[i] 的最大值;若要求炸弹 i 的范围,就是不停扩张的过程,最多扩张 log(n) 次。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define LL long long const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
LL read() {
LL x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 500010
#define maxlog 19
#define MOD 1000000007 int n, q[maxn], top, lft[maxn], rgt[maxn];
LL X[maxn], R[maxn]; int Log[maxn], mn[maxlog][maxn], mx[maxlog][maxn];
void init() {
for(int i = 1; i <= n; i++) mn[0][i] = lft[i], mx[0][i] = rgt[i];
for(int j = 1; (1 << j) <= n; j++)
for(int i = 1; i + (1 << j) - 1 <= n; i++)
mn[j][i] = min(mn[j-1][i], mn[j-1][i+(1<<j-1)]),
mx[j][i] = max(mx[j-1][i], mx[j-1][i+(1<<j-1)]);
return ;
}
int _l, _r;
void query(int ql, int qr) {
int t = Log[qr-ql+1];
_l = min(mn[t][ql], mn[t][qr-(1<<t)+1]);
_r = max(mx[t][ql], mx[t][qr-(1<<t)+1]);
return ;
} int main() {
n = read();
for(int i = 1; i <= n; i++) X[i] = read(), R[i] = read(); Log[1] = 0;
for(int i = 2; i <= n; i++) Log[i] = Log[i>>1] + 1; lft[1] = 1;
q[top = 1] = 1;
for(int i = 2; i <= n; i++) {
int l = 1, r = top;
while(l < r) {
int mid = l + r >> 1;
if(X[q[mid]] < X[i] - R[i]) l = mid + 1; else r = mid;
}
if(X[q[l]] < X[i] - R[i]) lft[i] = i;
else lft[i] = lft[q[l]];
while(top && lft[i] <= lft[q[top]]) top--;
q[++top] = i;
}
rgt[n] = n;
q[top = 1] = n;
for(int i = n - 1; i; i--) {
int l = 1, r = top;
while(l < r) {
int mid = l + r >> 1;
if(X[q[mid]] > X[i] + R[i]) l = mid + 1; else r = mid;
}
// printf("%d: %d | %d %lld\n", i, l, q[l], X[q[l]]);
if(X[q[l]] > X[i] + R[i]) rgt[i] = i;
else rgt[i] = rgt[q[l]];
while(top && rgt[i] >= rgt[q[top]]) top--;
q[++top] = i;
}
// for(int i = 1; i <= n; i++) printf("LR [%d %d]\n", lft[i], rgt[i]);
init();
int ans = 0;
for(int i = 1; i <= n; i++) {
int l = lft[i], r = rgt[i];
_l = n + 1; _r = 0;
for(;;) {
query(l, r);
if(l == _l && r == _r) break;
l = _l; r = _r;
}
ans += ((LL)i * (r - l + 1)) % MOD;
if(ans >= MOD) ans -= MOD;
// printf("[%d, %d]\n", l, r);
} printf("%d\n", ans); return 0;
}

[LOJ#2255][BZOJ5017][Snoi2017]炸弹的更多相关文章

  1. loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点

    loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点 链接 loj 思路 用交错关系建出图来,发现可以直接缩点,拓扑统计. 完了吗,不,瓶颈在于边数太多了,线段树优化建图. 细节 ...

  2. loj #2255. 「SNOI2017」炸弹

    #2255. 「SNOI2017」炸弹 题目描述 在一条直线上有 NNN 个炸弹,每个炸弹的坐标是 XiX_iX​i​​,爆炸半径是 RiR_iR​i​​,当一个炸弹爆炸时,如果另一个炸弹所在位置 X ...

  3. [bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

    5017: [Snoi2017]炸弹 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 608  Solved: 190[Submit][Status][ ...

  4. BZOJ5017 Snoi2017炸弹(线段树+强连通分量+缩点+传递闭包)

    容易想到每个炸弹向其能引爆的炸弹连边,tarjan缩点后bitset传递闭包.进一步发现每个炸弹能直接引爆的炸弹是一段连续区间,于是线段树优化建图即可让边的数量降至O(nlogn).再冷静一下由于能间 ...

  5. BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]

    方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...

  6. bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)

    https://www.lydsy.com/JudgeOnline/problem.php?id=5017 暴力: 对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹 如果能,由这个炸弹向引爆 ...

  7. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  8. bzoj5017: [Snoi2017]炸弹

    Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被 ...

  9. bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...

随机推荐

  1. UVA Planning mobile robot on Tree树上的机器人(状态压缩+bfs)

    用(x,s)表示一个状态,x表示机器人的位置,s表示其他位置有没有物体.用个fa数组和act数组记录和打印路径,转移的时候判断一下是不是机器人在动. #include<bits/stdc++.h ...

  2. 陆教授浅谈5G毫米波手机天线技术的发展现状和未来的应用场景

    近日,香港城大电子工程学系讲座教授陆贵文教授荣获英国皇家工程院院士荣衔,以表彰他在推动天线研究的卓越贡献.他研发的天线由L形探针馈电微带天线.磁电耦极天线,以至5G毫米波手机天线等技术,均在天线领域影 ...

  3. 手机屏幕材质详解(TFT,TPS,OLED,AMOLED等)

    手机屏幕概括起来就是两种,一个是LCD,一个是OLED屏幕,这两个是屏幕显示技术的两大基础. 一 . LCD:Liquid Crystal Display,这是一种介于固态和液态之间的物质,称为液晶技 ...

  4. 数据预处理之数据规约(Data Reduction)

    数据归约策略 数据仓库中往往具有海量的数据,在其上进行数据分析与挖掘需要很长的时间 数据归约 用于从源数据中得到数据集的归约表示,它小的很多,但可以产生相同的(几乎相同的)效果 数据归约策略 维归约  ...

  5. [vijos]P1642 班长的任务

    背景 十八居士的毕业典礼(1) 描述 福州时代中学2009届十班同学毕业了,于是班长PRT开始筹办毕业晚会,但是由于条件有限,可能每个同学不能都去,但每个人都有一个权值,PRT希望来的同学们的权值总和 ...

  6. 【启发式拆分】bzoj5200: [NWERC2017]Factor-Free Tree

    和bzoj4059: [Cerc2012]Non-boring sequences非常相似 Description 一棵Factor-Free Tree是指一棵有根二叉树,每个点包含一个正整数权值,且 ...

  7. matplotlib绘图股票走势图实践

    导入模块 import pandas as pdimport numpy as npfrom pandas import Series,DataFrameimport matplotlib.pyplo ...

  8. python入门:数字型和字符串换行要同类型 注意连接符

    #!/usr/bin/env python # -*- coding: utf-8 -*- #数字型和字符串换行要同类型 注意连接符 a = 1 b = 2 print(str(a) + " ...

  9. Vue表单输入绑定

    <h3>基础用法</h3> <p>你可以用<strong>v-model</strong>指令在表单input,textarea以及sele ...

  10. 在WIN2008R2的IIS7环境下安装PHP5.6.15

    1.下载PHP5.6.15 在http://windows.php.net/download页面中找到VC11 x64 Non Thread Safe下载ZIP版. 2.将下载的压缩包解压到D盘PHP ...