[Snoi2017] bzoj 5017 - 炸弹 - tarjan - 倍增

注意到一个炸弹爆炸后,最终爆炸范围一定是一个区间,只需要维护这个区间按即可。用倍增表维护出,一个炸弹爆炸之后,能引爆的所有炸弹中,左、右端点最远的两枚炸弹,从当前向这两个连边;而其余炸弹可以不用管。然后对于这个图跑tarjan缩点,也就是同一个强连通分量里面的炸弹可以相互引爆,共享左右端点;然后每个点的区间就是其所有后继状态的并,最后询问这个区间内有多少炸弹即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<stack>
#include<queue>
#include<utility>
#include<climits>
#define mp make_pair
#define lint long long
#define N 510000
#define LOG 20
#define M N<<1
#define INF INT_MAX
#define mod 1000000007
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
lint v[N],x[N],r[N];pii fL[N][LOG],fR[N][LOG];int minL[N],scc;
int a[M],b[M],low[N],dfn[N],d[N],Log[N],t[N],maxR[N],cnt[N];
stack<int> s;int state[N],dfc,bel[N],L[N],R[N];bool vis[N];
struct edges{
    int to,pre;
}e[M];int h[N],etop;queue<int> q;
inline int add_edge(int u,int v)
{
    return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop;
}
inline int tarjan(int x)
{
    s.push(x),state[x]=1,low[x]=dfn[x]=++dfc;
    for(int i=h[x],y;i;i=e[i].pre)
        if(!state[y=e[i].to]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(state[y]==1) low[x]=min(low[x],dfn[y]);
    if(low[x]==dfn[x])
    {
        bel[x]=++scc,minL[scc]=L[x],maxR[scc]=R[x];int y;
        while(s.top()^x)
            bel[y=s.top()]=scc,minL[scc]=min(minL[scc],L[y]),
            maxR[scc]=max(maxR[scc],R[y]),s.pop(),state[y]=2;
        s.pop(),state[x]=2;
    }
    return 0;
}
inline int toposort(int n)
{
    int p=0;
    for(int i=1;i<=n;i++)
        if(!d[i]) q.push(i),vis[i]=true,t[++p]=i;
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=h[x],y;i;i=e[i].pre)
            if(!(--d[y=e[i].to])) q.push(y),vis[y]=true,t[++p]=y;
    }
    return 0;
}
inline int getdp(int n)
{
    for(int p=n;p>=1;p--)
        for(int x=t[p],i=h[x],y;i;i=e[i].pre)
            y=e[i].to,minL[x]=min(minL[x],minL[y]),maxR[x]=max(maxR[x],maxR[y]);
    return 0;
}
inline int queryL(int L,int R)
{
    int k=Log[R-L+1];
    return min(fL[L][k],fL[R-(1<<k)+1][k]).second;
}
inline int queryR(int L,int R)
{
    int k=Log[R-L+1];
    return max(fR[L][k],fR[R-(1<<k)+1][k]).second;
}
#define gc getchar()
inline lint inn()
{
    lint x;int ch,f=0;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
    if(ch^'-') x=ch^'0';else f=1,x=0ll;
    while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
    return f?-x:x;
}
int main()
{
    int n,c=0,ec=0;scanf("%d",&n);
    v[++c]=LLONG_MIN,v[++c]=LLONG_MAX;
    for(int i=1;i<=n;i++)
        x[i]=inn(),r[i]=inn(),v[++c]=x[i];
    sort(v+1,v+c+1),c=unique(v+1,v+c+1)-v-1;
    for(int i=1;i<=n;i++)
        L[i]=lower_bound(v+1,v+c+1,x[i]-r[i])-v,
        R[i]=lower_bound(v+1,v+c+1,x[i]+r[i])-v,
        (v[R[i]]>(x[i]+r[i]))?(R[i]--):0,
        x[i]=lower_bound(v+1,v+c+1,x[i])-v;
    for(int i=1;i<=c;i++)
        cnt[i]=0,fL[i][0]=mp(INF,0),fR[i][0]=mp(0,0);
    for(int i=1;i<=n;i++) cnt[x[i]]++,
        fL[x[i]][0]=min(fL[x[i]][0],mp(L[i],i)),
        fR[x[i]][0]=max(fR[x[i]][0],mp(R[i],i));
    for(int i=2;i<=c;i++)
        Log[i]=Log[i>>1]+1,cnt[i]+=cnt[i-1];
    for(int j=1;j<=Log[c];j++)
        for(int i=1;i+(1<<j)-1<=c;i++)
            fL[i][j]=min(fL[i][j-1],fL[i+(1<<(j-1))][j-1]),
            fR[i][j]=max(fR[i][j-1],fR[i+(1<<(j-1))][j-1]);
    for(int i=1,u,v;i<=n;i++)
        u=queryL(L[i],R[i]),v=queryR(L[i],R[i]),
        (u?add_edge(i,u):0),(v?add_edge(i,v):0);
    for(int i=1;i<=n;i++) if(!state[i]) tarjan(i);
    for(int x=1;x<=n;x++)
        for(int i=h[x];i;i=e[i].pre)
            if(bel[x]^bel[e[i].to])
                ec++,a[ec]=bel[x],b[ec]=bel[e[i].to];
    memset(h,0,sizeof(h)),etop=0;
    for(int i=1;i<=ec;i++)
        add_edge(a[i],b[i]),d[b[i]]++;
    toposort(scc),getdp(scc);int ans=0;
    for(int i=1;i<=n;i++)
        (ans+=(lint)i*(cnt[maxR[bel[i]]]-cnt[minL[bel[i]]-1])%mod)%=mod;
    return !printf("%d\n",ans);
}


猜你喜欢

转载自blog.csdn.net/mys_c_k/article/details/79979245
今日推荐