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. 极客时间 mysql实战45讲下载读 08讲事务到底是隔离的还是不隔离的 笔记

    笔记体会: 1.innodb支持RC和RR隔离级别实现是用的一致性视图(consistent read view) 2.事务在启动时会拍一个快照,这个快照是基于整个库的.基于整个库的意思就是说一个事务 ...

  2. Xshell调整终端显示的最大行数(缓冲区)

    1 选择会话,按顺序点击文件->属性 ,打开"会话属性"窗口 如下 在"会话属性"窗口中选择“终端” 修改缓冲区大小的值:其范围为0~2147483647 ...

  3. PostgreSQL 数据库性能调优的注意点

    PostgreSQL提供了一些性能调优的功能.主要有如下几个方面.1.使用EXPLAIN   EXPLAIN命令可以查看执行计划,这个方法是我们最主要的调试工具. 2.及时更新执行计划中使用的统计信息 ...

  4. 理解ZBrush中的笔触

    笔触主要配合笔刷来使用,同样的笔刷搭配不同的笔触可以绘制出各种不同的效果.简言之,ZBrush 4R8就是提供了各种各样的笔触效果,例如,有模拟连贯笔触的效果,也有模拟喷枪喷洒的笔触效果. 下面简单认 ...

  5. Matlab从入门到精通 Chapter5 数据可视化--

    5-1 图形绘制示例 >> x2=-17:0.02:3; >> y2=1./((x2+3).^2+1)+1./((x2+9).^2+4)+5; >> subplot ...

  6. Vue中两种传值方式

    第一种:通过url传参,直接在地址后加? ,通过this.$route.query对象获取 第二种:通过路由传参,修改路由,通过this.$route.params对象获取

  7. vue:element-ui时间选择器限制只能点不能输入

    原文链接:点我 <el-form-item label="门店成立日期" prop="storeSetupDate"> <template&g ...

  8. execlp(3) - Linux手册

    名称: execl, execlp, execle, execv, execvp, execvpe:执行文件 总览: #include <unistd.h> extern char **e ...

  9. 紫书 例题 11-3 UVa 1151 (有边集的最小生成树+二进制枚举子集)

    标题指的边集是说这道题的套餐, 是由几条边构成的. 思路是先做一遍最小生成树排除边, 因为如果第一次做没有加入的边, 到后来新加入了很多权值为0的边,这些边肯定排在最前面,然后这条边的前面的那些边肯定 ...

  10. 使用vuex的流程随笔

    1.在建好的vue项目中新建一个vuex文件夹在此文件夹下建一个index.js文件,在此文件下引入vuex 模块(当然需要先npm下载)和vue模块,在引入你所有的自定义的module.js模块(下 ...