解题思路
嗯,我觉得看出是个有向图并不难
把每个炸弹向他能炸到的连一条边
然后缩点,那么每个炸弹一定能炸到他所属的强连通分量里的所有炸弹
缩完点后是一个DAG,那么对于新图上的每个点来说,他在DAG上能到达所有店都能炸到
并且我们能发现一个性质,一个炸弹能炸到的一定是连续的一段,所以我们建这个DAG的反图,进行DP,更新能炸到的左端点和右端点
但是数据有点大,所以一个一个连边就会T
一般情况,我们会选择线段树优化建图
但是众所周知,线段树优化建图细节很多,很难调
所以我们要另想一种方法优化
举个栗子
如果A能炸到B,我们记作A->B
如果按顺序有三个点A,B,C
A->C,B->C,A->B
那么A->C这条边是没有必要的,所以对于每个炸弹,我们只从左边第一个能炸到他的炸弹向他连一条边,右边同理,这个可以用单调栈维护
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+7;
typedef long long LL;
const LL mod = 1e9+7;
struct node
{
LL y,next;
}e[4*N],ec[4*N];
LL link[N],linkc[N],tc,t=0;
LL deg[N];
void add(LL x,LL y)
{
t++;
e[t].y=y;
e[t].next=link[x];
link[x]=t;
}
void addc(LL x,LL y)
{
tc++;
ec[tc].y=y;
ec[tc].next=linkc[x];
deg[y]++;
linkc[x]=tc;
}
LL pos[N],sum=0,range[N],L[N],R[N];
LL n;
inline LL read()
{
LL X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
LL st[N],top,Lx[N],Rx[N];
LL low[N],dfn[N],num,cnt=0,bel[N];
bool ins[N];
vector<LL> scc[N];
void tarjan(LL x)
{
dfn[x]=low[x]=++num;
st[++top]=x;
ins[x]=1;
for(LL i=link[x];i;i=e[i].next)
{
LL y=e[i].y;
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y])
low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x])
{
cnt++;
LL y;
do
{
y=st[top--];
ins[y]=0;
bel[y]=cnt;
Lx[cnt]=min(Lx[cnt],y);
Rx[cnt]=max(Rx[cnt],y);
scc[cnt].push_back(y);
}while(x!=y);
}
}
queue<LL> q;
void topsort()
{
for(LL i=1;i<=n;i++)
if(deg[i]==0) q.push(i);
while(!q.empty())
{
LL x=q.front();
q.pop();
for(LL i=linkc[x];i;i=ec[i].next)
{
LL y=ec[i].y;
if(deg[y]<=0) continue;
deg[y]--;
Lx[y]=min(Lx[y],Lx[x]);
Rx[y]=max(Rx[y],Rx[x]);
if(deg[y]==0) q.push(y);
}
}
}
int main()
{
n=read();
for(LL i=1;i<=n;i++)
{
pos[i]=read();
range[i]=read();
L[i]=pos[i]-range[i];
R[i]=pos[i]+range[i];
}
for(int i=1;i<=n;i++)
{
Rx[i]=-1e18-9;
Lx[i]=1e18+9;
}
for(LL i=1;i<=n;i++)
{
while(top&&R[st[top]]<pos[i]) --top;
if(top) add(st[top],i);
while(top&&R[st[top]]<=R[i]) --top;
st[++top]=i;
}
memset(st,0,sizeof(st));
top=0;
for(LL i=n;i>=1;i--)
{
while(top&&L[st[top]]>pos[i]) --top;
if(top) add(st[top],i);
while(top&&L[st[top]]>=L[i]) --top;
st[++top]=i;
}
memset(st,0,sizeof(st));
top=0;
for(LL i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
for(LL x=1;x<=n;x++)
{
for(LL i=link[x];i;i=e[i].next)
{
LL y=e[i].y;
if(bel[x]==bel[y]) continue;
addc(bel[y],bel[x]);
}
}
topsort();
for(LL i=1;i<=n;i++)
sum=(sum+i*(Rx[bel[i]]-Lx[bel[i]]+1)%mod)%mod;
cout<<sum;
return 0;
}