题目大意
在一条直线上有 N 个炸弹,每个炸弹的座标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:
Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。
对于i等于1到n,求把第i个炸弹引爆会导致多少个炸弹爆炸。
n≤500000,|Xi|≤
分析
首先引爆的炸弹肯定是一个区间。
那么可以找引爆i后最终爆炸区间的两个端点来求答案。
可以尝试给i向j连有向边边,表示i爆炸后可以直接引爆j,然后在i能到达的点里面找最小、最大值。
但是这样连边的复杂度很大,注意到直接引爆的也是一个区间,那么用线段树优化连边即可。
接下来就是找一个点能到达的点的编号的极值。可以跑一遍Tarjan缩强连通分量,然后原图变成一个DAG,接下来跑个拓扑序,然后倒过来扫一遍即可。
时间复杂度
#include <cstdio>
#include <cstring>
#include <algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int N=5e5+5,Log=19,mo=1e9+7,M=1048588,T=N*45;
typedef long long LL;
int n,m,ans,tot,h[M],e[T],nxt[T],Id[M],H[M],E[T],Nxt[T],dfn[M],low[M],Top,st[M],Mi[M],Mx[M],ID[N],D[M],de[M];
bool vis[M],bz[M];
LL X[N],R[N];
char c;
LL read()
{
LL x=0; int sig=1;
for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;
for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
return x*sig;
}
void add(int x,int y)
{
e[++tot]=y; nxt[tot]=h[x]; h[x]=tot;
}
void Out(int l,int r,LL a,LL b,int v,int x)
{
if (a<=X[l] && b>=X[r])
{
add(ID[v],x); return;
}
int mid=l+r>>1;
if (a<=X[mid]) Out(l,mid,a,b,v,x<<1);
if (b>=X[mid+1]) Out(mid+1,r,a,b,v,x<<1|1);
}
void Link(int l,int r,int x)
{
if (l==r)
{
ID[l]=x; return;
}
int mid=l+r>>1;
add(x,x<<1); add(x,x<<1|1);
Link(l,mid,x<<1); Link(mid+1,r,x<<1|1);
}
void Tarjan(int x)
{
low[x]=dfn[x]=++tot;
vis[x]=bz[x]=1; st[++Top]=x;
for (int i=h[x];i;i=nxt[i])
{
if (!vis[e[i]])
{
Tarjan(e[i]); low[x]=min(low[x],low[e[i]]);
}else if (bz[e[i]]) low[x]=min(low[x],low[e[i]]);
}
if (dfn[x]==low[x])
{
m++;
for (;st[Top+1]!=x;Id[st[Top--]]=m) bz[st[Top]]=0;
}
}
void Add(int x,int y)
{
E[++tot]=y; Nxt[tot]=H[x]; H[x]=tot; de[y]++;
}
int main()
{
n=read();
for (int i=1;i<=n;i++) X[i]=read(),R[i]=read();
Link(1,n,1);
for (int i=1;i<=n;i++) Out(1,n,X[i]-R[i],X[i]+R[i],i,1);
tot=0;
for (int i=1;i<=ID[n];i++) if (!vis[ID[i]]) Tarjan(ID[i]);
tot=0;
for (int i=1;i<M;i++)
for (int j=h[i];j;j=nxt[j]) if (Id[i]!=Id[e[j]]) Add(Id[i],Id[e[j]]);
memset(Mi,127,sizeof(Mi));
for (int i=1;i<=n;i++) Mi[Id[ID[i]]]=min(Mi[Id[ID[i]]],i),Mx[Id[ID[i]]]=max(Mx[Id[ID[i]]],i);
tot=0;
for (int i=1;i<=m;i++) if (!de[i]) D[++tot]=i;
for (int i=1,j,x;i<=tot;i++)
{
x=D[i];
for (j=H[x];j;j=Nxt[j])
{
de[E[j]]--;
if (!de[E[j]]) D[++tot]=E[j];
}
}
for (int i=n,j,x;i;i--)
{
x=D[i];
for (j=H[x];j;j=Nxt[j]) Mi[x]=min(Mi[x],Mi[E[j]]),Mx[x]=max(Mx[x],Mx[E[j]]);
}
ans=0;
for (int i=1;i<=n;i++) ans=(ans+1ll*i*(Mx[Id[ID[i]]]-Mi[Id[ID[i]]]+1))%mo;
printf("%d\n",ans);
return 0;
}