Description

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

Input

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

Output

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

题解

因为每一个炸弹爆炸后引爆的是一个区间的炸弹,所以想到线段树优化建图。

然后可能有环所以跑Tarjan求强连通分量。最后拓扑合并答案。

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int N=;
const int mod=1e9+;
queue<int> q;
int cnt,cnt1,head[N*],head1[N*];
int num,id[N*],di[N*];
int dfn[N*],low[N*],tot1,top,stack[N*],book[N*],num1,col[N*],tmp;
long long a[N],r[N],b[N],maxx[N*],minn[N*];
int n,tot,in[N*];
long long ans;
struct tree{
int l,r;
}tr[N*];
struct edge{
int to,nxt,u;
}e[N*],e1[N*];
void add(int u,int v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].u=u;
e[cnt].to=v;
head[u]=cnt;
}
void add1(int u,int v){
cnt1++;
e1[cnt1].nxt=head1[u];
e1[cnt1].to=v;
head1[u]=cnt1;
}
void build(int l,int r,int now){
num=max(num,now);
tr[now].l=l;tr[now].r=r;
if(r==l){
id[l]=now;
di[now]=l;
return;
}
int mid=(tr[now].l+tr[now].r)>>;
build(l,mid,now*);
build(mid+,r,now*+);
add(now,now*);
add(now,now*+);
}
void update(int l,int r,int now,int u){
if(tr[now].l==l&&tr[now].r==r){
add(u,now);
return;
}
int mid=(tr[now].l+tr[now].r)>>;
if(l>mid)update(l,r,now*+,u);
else if(r<=mid)update(l,r,now*,u);
else{
update(l,mid,now*,u);
update(mid+,r,now*+,u);
}
}
void Tarjan(int u){
dfn[u]=low[u]=++tot1;
stack[++top]=u;
book[u]=;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dfn[v]==){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(book[v])low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
int x;
num1++;
minn[num1]=4e18;
maxx[num1]=-4e18;
bool flag=false;
do{
x=stack[top--];
book[x]=;
col[x]=num1;
if(di[x]){
if(!flag){
minn[num1]=a[di[x]]-r[di[x]];
maxx[num1]=a[di[x]]+r[di[x]];
flag=true;
}
else{
minn[num1]=min(minn[num1],a[di[x]]-r[di[x]]);
maxx[num1]=max(maxx[num1],a[di[x]]+r[di[x]]);
}
}
}while(x!=u);
}
}
int lower(long long x){
int ll=;int rr=tot+;
while(ll<=rr){
int mid=(ll+rr)>>;
if(b[mid]>=x){
tmp=mid;
rr=mid-;
}
else ll=mid+;
}
return tmp;
}
int uppr(long long x){
int ll=;int rr=tot+;
while(ll<=rr){
int mid=(ll+rr)>>;
if(b[mid]>x){
tmp=mid;
rr=mid-;
}
else ll=mid+;
}
return tmp;
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%lld%lld",&a[i],&r[i]);
b[i]=a[i];
}
tot=unique(b+,b++n)-(b+);
b[tot+]=4e18;
build(,n,);
for(int i=;i<=n;i++){
int x=lower(a[i]-r[i]);
int y=uppr(a[i]+r[i])-;
update(x,y,,id[i]);
}
for(int i=;i<=num;i++){
if(!dfn[i])Tarjan(i);
}
for(int i=;i<=cnt;i++){
if(col[e[i].u]==col[e[i].to])continue;
add1(col[e[i].to],col[e[i].u]);
in[col[e[i].u]]++;
}
for(int i=;i<=num1;i++){
if(in[i]==)q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head1[u];i;i=e1[i].nxt){
int v=e1[i].to;
in[v]--;
if(in[v]==)q.push(v);
minn[v]=min(minn[v],minn[u]);
maxx[v]=max(maxx[v],maxx[u]);
}
}
for(int i=;i<=n;i++){
int x=uppr(maxx[col[id[i]]])-;
int y=lower(minn[col[id[i]]]);
ans+=(long long)((long long)(x-y+)*(long long)i)%mod;
ans%=mod;
}
printf("%lld",ans);
return ;
}

BZOJ5017 炸弹(线段树优化建图+Tarjan+拓扑)的更多相关文章

  1. bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)

    直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...

  2. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

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

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

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

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

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

  5. 『炸弹 线段树优化建图 Tarjan』

    炸弹(SNOI2017) Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸 时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi ...

  6. 模拟赛T2 线段树优化建图+tarjan+拓扑排序

    然而这只是 70pts 的部分分,考场上没想到满分怎么做(现在也不会) code: #include <cstdio> #include <string> #include & ...

  7. 炸弹:线段树优化建边+tarjan缩点+建反边+跑拓扑

    这道题我做了有半个月了...终于A了... 有图为证 一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案 首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以 ...

  8. 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)

    题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...

  9. [SNOI2017]炸弹[线段树优化建图]

    [SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...

随机推荐

  1. 51nod 1272 最大距离 O(nlog(n)) , 快排 , 最大连续子串

    题目: 解法:排序,把值小的和索引小的放在前面,记录一下之前索引最小的就可以了. 没什么可以讲的,上代码吧: #include <bits\stdc++.h> using namespac ...

  2. 前端的console.log的效果写法

    不说废话,直接上代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> ...

  3. Docker学习笔记(1)----认识Docker

    1. 什么Docker? Docker是一个能把开发的应用程序自动部署到容器的引擎,它使用go语言编写的开源引擎,它在github上面个的地址为:https://github.com/docker/d ...

  4. Matlab--从入门到精通(Chapter3 矩阵运算)

          数值计算可以分为两类:矩阵运算和矩阵元素运算 3.1 矩阵函数和特殊矩阵        矩阵代数的处理数组大部分以一维数组(向量)和二维数组(矩阵)为主. 常见的矩阵处理函数如下: 特殊矩 ...

  5. Python读取Matlab的.mat文件

    参考网站: https://blog.csdn.net/rumswell/article/details/8545087 数据: R 22*22 double 部分截图如下: 使用sicpy.io即可 ...

  6. 利用SignalR来同步更新Winfrom

    之前写了个用Socket来更新多个Winfrom的试例,这两天看了下SignalR,也用这个来试一下 SignalR 地址:https://www.asp.net/signalr 我这个也是基于 ht ...

  7. webkit Safari的样式库

    1,webkit Box模型 CSS定义:-webkit-border-bottom-left-radius: radius; CSS定义:-webkit-border-top-left-radius ...

  8. 使用maven插件dockerfile-maven-plugin生成Docker镜像并推送到镜像仓库

    1.引入maven插件 <build> <plugins> <plugin> <groupId>com.spotify</groupId> ...

  9. GIT配置多用户

    在公司工作的时候有时候想提交一点代码到github上,然后一台电脑上就需要配置两个账号分别访问github和公司的gitlab 1. 分别生成两个key 为什么要生成两个key的原因我也不清楚,望路过 ...

  10. OpenJDK源码研究笔记(三)-RandomAccess等标记接口的作用

    标识接口是没有任何方法和属性的接口. 它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情. 下面来看一个标记接口RandomAccess. public interface Rando ...