题目大意:在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:
Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。
现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢?
题解:若x能引爆y,add(x,y),易知i的答案即为i能到达的编号max-编号min+1
考虑到i的连边是一个区间,可以用线段树优化建图
跑一遍Tarjan缩强连通分量,然后原图变成一个DAG,接下来跑个拓扑序,然后倒过来扫一遍即可
我的收获:各种套路……
#include <bits/stdc++.h>
using namespace std;
const int P=1e9+7;
#define INF LLONG_MAX/2
#define ll long long
#define N 2500005
int n,sz,num[N];
ll X[N],R[N];
int t,head[N];
int dfn[N],low[N],col[N],in[N];
int scnt,tim,stk[N],top;
ll mi[N],mx[N];
bool ins[N];
vector<int> G[N],q;
struct edge{int fr,to,nex;}e[N<<3];
void add(int u,int v){e[t].fr=u,e[t].to=v,e[t].nex=head[u],head[u]=t++;}
struct SegmentTree{
#define ls x<<1
#define rs x<<1|1
#define lson l,mid,x<<1
#define rson mid+1,r,x<<1|1
#define root 1,n,1
void build(int l,int r,int x)
{
num[x]=++sz;
if(l==r){add(num[x],l);return ;}
int mid=l+r>>1;
build(lson),build(rson);
add(num[x],num[ls]),add(num[x],num[rs]);
}
void update(int L,int R,int ot,int l,int r,int x)
{
if(L<=l&&r<=R){add(ot,num[x]);return ;}
int mid=l+r>>1;
if(L<=mid) update(L,R,ot,lson);
if(R>mid) update(L,R,ot,rson);
}
}T;
void tarjan(int x){
int now=0;
dfn[x]=low[x]=++tim;
stk[++top]=x;ins[x]=1;
for(int i=head[x];i!=-1;i=e[i].nex){
int v=e[i].to;
if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
else if(ins[v]) low[x]=min(low[x],dfn[v]);
}
if(low[x]==dfn[x]){
scnt++;mi[scnt]=INF,mx[scnt]=-INF;
while(x!=now){
now=stk[top--];ins[now]=0;col[now]=scnt;
if(now<=n) mi[scnt]=min(mi[scnt],(ll)now),mx[scnt]=max(mx[scnt],(ll)now);
}
}
}
void rebuild()
{
for(int i=0;i<t;i++)
if(col[e[i].fr]!=col[e[i].to])
G[col[e[i].fr]].push_back(col[e[i].to]),in[col[e[i].to]]++;
}
void toposort()
{
for(int i=1;i<=scnt;i++) if(!in[i]) q.push_back(i);
for(int x=0;x<q.size();x++)
{
int u=q[x];
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
in[v]--;if(!in[v]) q.push_back(v);
}
}
for(int i=scnt;i;i--){
int x=q[i-1];
for(int j=0;j<G[x].size();j++) mi[x]=min(mi[x],mi[G[x][j]]),mx[x]=max(mx[x],mx[G[x][j]]);
}
}
void work()
{
for(int i=1;i<=sz;i++) if(!dfn[i]) tarjan(i);
rebuild();toposort();
ll ans=0;
for(int i=1;i<=n;i++) ans+=1ll*i*(mx[col[i]]-mi[col[i]]+1),ans%=P;
printf("%lld\n",ans);
}
void init()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);sz=n;T.build(root);
for(int i=1;i<=n;i++) scanf("%lld%lld",&X[i],&R[i]);
for(int i=1;i<=n;i++) T.update(lower_bound(X+1,X+n+1,X[i]-R[i])-X,upper_bound(X+1,X+n+1,X[i]+R[i])-X-1,i,root);
}
int main()
{
init();
work();
return 0;
}