bzoj5017: [Snoi2017]炸弹

Posted ccz181078

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj5017: [Snoi2017]炸弹相关的知识,希望对你有一定的参考价值。

Description

在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: 
Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 
现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? 

Input

第一行,一个数字 N,表示炸弹个数。 
第 2∼N+1行,每行 2 个数字,表示 Xi,Ri,保证 Xi 严格递增。 
N≤500000
−10^18≤Xi≤10^18
0≤Ri≤2×10^18

Output

一个数字,表示Sigma(i*炸弹i能引爆的炸弹个数),1<=i<=N mod10^9+7。 

如果一个炸弹能引爆另一个,就对应连一条有向边,询问即为查询每个点能到达的点中最左和最右分别是哪一个。由于边数较多,需要线段树优化建图,然后用tarjan将强连通分量缩点,缩点后在得到的DAG上逆拓扑序递推一下。时间复杂度O(nlogn),空间复杂度O(n)(线段树上的区间连边不需要记录,只要动态计算即可)。

#include<bits/stdc++.h>
typedef long long i64;
const int P=1e9+7,N=5e5+7;
char buf[N*50],*ptr=buf-1;
i64 _(){
    i64 x=0;
    int c=*++ptr,f=1;
    while(c<48)c==-?f=-1:0,c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x*f;
}
int n,mx,tk=0,ss[1<<20|111],sp=0,ans=0;
i64 xs[N],rs[N];
void mins(int&a,int b){if(a>b)a=b;}
void maxs(int&a,int b){if(a<b)a=b;}
struct node{
    int l,r,dfn,low;
    bool in;
    void chk0(node&w){
        mins(l,w.l),maxs(r,w.r);
    }
    void chk1(node&w){
        mins(low,w.low);
        chk0(w);
    }
    void chk2(node&w){
        if(w.in)mins(low,w.dfn);
        chk0(w);
    }
}ns[1<<20|111];
void tj(int);
void tje(int w,int u){
    if(!ns[u].dfn){
        tj(u);
        ns[w].chk1(ns[u]);
    }else ns[w].chk2(ns[u]);
}
void tj(int w){
    ns[w].dfn=ns[w].low=++tk;
    ns[w].in=1;
    ss[++sp]=w;
    if(!ns[w].l)ns[w].l=n+1;
    if(w<mx){
        tje(w,w<<1);
        tje(w,w<<1^1);
    }else{
        for(int l=mx+ns[w].l-1,r=mx+ns[w].r+1;r-l>1;l>>=1,r>>=1){
            if(~l&1)tje(w,l+1);
            if(r&1)tje(w,r-1);
        }
    }
    if(ns[w].dfn==ns[w].low){
        int u;
        do{
            ns[u=ss[sp--]].in=0;
            ns[u].chk0(ns[w]);
        }while(u!=w);
    }
}
int main(){
    fread(buf,1,sizeof(buf),stdin);
    n=_();
    for(int i=1;i<=n;++i)xs[i]=_(),rs[i]=_();
    for(mx=1;mx<=n+2;mx<<=1);
    for(int i=1;i<=n;++i){
        ns[mx+i].l=std::lower_bound(xs+1,xs+n+1,xs[i]-rs[i])-xs;
        ns[mx+i].r=std::upper_bound(xs+1,xs+n+1,xs[i]+rs[i])-xs-1;
    }
    tj(1);
    for(int i=1;i<=n;++i){
        node&w=ns[mx+i];
        ans=(ans+i64(i)*(w.r-w.l+1))%P;
    }
    printf("%d\n",ans);
    return 0;
}

 

以上是关于bzoj5017: [Snoi2017]炸弹的主要内容,如果未能解决你的问题,请参考以下文章

bzoj5017: [Snoi2017]炸弹

[bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

P5025 [SNOI2017]炸弹 线段树优化建图+缩点+DAG图上DP

BZOJ5015[Snoi2017]礼物 矩阵乘法

BZOJ5018[Snoi2017]英雄联盟 背包