[LOJ#2255][BZOJ5017][Snoi2017]炸弹
看到这题首先想到了线段树优化建边, 我们将可以炸到的炸弹之间连上单向边,然后缩点,拓扑一下什么的就可以求出来每个问题的解了。 虽然不是正解,但貌似可做。
我们可以想一想这道题是否存在一些有趣的性质,可以让我们优化建边。 假设点a在点b左侧,如果a点能炸到点b且a是离b最近的能炸到b的点,那么其他位于b左侧且能炸到b的点一定也能炸到a,所以我们只需要将一个点向左右两侧离它最近的且能炸到它的点建边就好了。然后缩点,拓扑。
开始是想着和T3一样用bitset,然而数据范围太大,时间和空间都承受不了,但是想想可以发现,每个炸弹能炸到的是连续的一段,所以可以记录每个scc能炸到的边界,在拓扑时对L取min,对R取max。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#define int LL
#define LL long long
#define mod 1000000007
#define MAXN 500010
using namespace std;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
#define u2(x) ed2[x].u
#define v2(x) ed2[x].v
#define n2(x) ed2[x].nxt
}ed[1000000],ed2[1000000];
int first[MAXN],num_e;
#define f(x) first[x]
int first2[MAXN],num_e2;
#define f2(x) first2[x]
int n,du[MAXN];
int x[MAXN],r[MAXN];
int dfn[MAXN],low[MAXN],cnt;
int stack[MAXN],top;
int belong[MAXN],tot;
bool v[MAXN];
vector<int> scc[MAXN];
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
stack[++top]=x;v[x]=1;
for(int i=f(x);i;i=n(i))
if(!dfn[v(i)])tarjan(v(i)),low[x]=min(low[x],low[v(i)]);
else if(v[v(i)])low[x]=min(low[x],dfn[v(i)]);
if(low[x]==dfn[x])
{
++tot;v[x]=0;
while(stack[top]!=x)
{
v[stack[top]]=0;
belong[stack[top]]=tot;
scc[tot].push_back(stack[top--]);
}
belong[x]=tot;
scc[tot].push_back(stack[top--]);
}
}
int L[MAXN],R[MAXN];
inline void add(int u,int v);
inline void add2(int u,int v);
signed main()
{
// freopen("in.txt","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&x[i],&r[i]);
for(int i=1;i<=n;i++)
{
for(int j=i-1;j;j--) if(x[i]<=x[j]+r[j]){add(i,j);break;}
for(int j=i+1;j<=n;j++)if(x[i]>=x[j]-r[j]){add(i,j);break;}
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
for(int i=1;i<=num_e;i++)
if(belong[u(i)]!=belong[v(i)])
add2(belong[u(i)],belong[v(i)]),du[belong[v(i)]]++;
memset(L,0x7f,sizeof(L));
memset(R,-0x7f,sizeof(R));
for(int i=1;i<=tot;i++)
for(int j=0;j<scc[i].size();j++)
L[i]=min(L[i],scc[i][j]),R[i]=max(R[i],scc[i][j]);
queue<int> q;
for(int i=1;i<=tot;i++)
if(!du[i])q.push(i);
while(!q.empty())
{
int k=q.front();q.pop();
for(int i=f2(k);i;i=n2(i))
{
du[v2(i)]--;
if(!du[v2(i)])q.push(v2(i));
L[v2(i)]=min(L[v2(i)],L[k]);
R[v2(i)]=max(R[v2(i)],R[k]);
}
}
LL ans=0;
for(int i=1;i<=n;i++)
ans=(ans+i*(R[belong[i]]-L[belong[i]]+1))%mod;
printf("%lld\n",ans);
}
inline void add(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
inline void add2(int u,int v)
{
++num_e2;
u2(num_e2)=u;
v2(num_e2)=v;
n2(num_e2)=f2(u);
f2(u)=num_e2;
}