炸弹

题目描述

在一条直线上有 $n$ 个炸弹,每个炸弹的坐标是 $ x_i $,爆炸半径是 $ r_i $,当一个炸弹爆炸时,如果另一个炸弹所在位置 $ x_j $ 满足: $ |x_j-x_i| <= r_i $ ,那么,该炸弹也会被引爆。 现在,请你帮忙计算一下,先把第 $i$ 个炸弹引爆,将引爆多少个炸弹呢? 答案对 $10^9 + 7$ 取模

输入输出格式

输入格式

 

第一行,一个数字 $n$ ,表示炸弹个数。 第 $2 ~ n+1$ 行,每行两个整数,表示 $x_i$,$r_i$,保证 $x_i$ 严格递增。

输出格式

 

一个数字,表示 $\sum \limits_{i=1}^n i\times$ 炸弹 $i$ 能引爆的炸弹个数。

输入输出样例

输入样例 #1

4
1 1
5 1
6 5
15 15

输出样例 #1

32

N<=500000
-10e8<=x_i<=10e8

析:容易发现,只需要找到每个炸弹所能达到的最左边的炸弹和右边的炸弹即可。若暴力循环,时间复杂度为n方,考虑优化,因为要找的是最大,最小值,考虑用线段树,
  用线段树存储区间炸弹,每个叶子节点即为真正的炸弹,这样可以得到每个区间内的最大最小值
  存储前先预处理,二分找每个炸弹能炸到的左右最远的炸弹,储存编号
  最后就是查询,先将左右边界设为自己,尝试更新,若可以,则再次尝试更新。
  最后注意一下数据范围,线段树存储需要4倍空间!!!

 


#include<bits/stdc++.h>
#define re register int
#define ll long long
#define N 10000100
#define mo 1000000007
ll n;
ll x[N],d[N],l[N],r[N];
ll ans;
ll xx,yy,x_now,y_now;
struct TREE
{
    ll tl,tr,p;
}use[N];
using namespace std;
inline long long read()
{
    char c=getchar();
    ll x=0,f=1;
    while(c>'9'||c<'0')
    {
        if(c=='-')
            f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void build(ll k,ll L,ll R)
{
    if(L==R)
    {
        use[k].tl=l[L];
        use[k].tr=r[L];
        return;
    }
    ll m=(L+R)>>1;
    build(k<<1,L,m);
    build(k<<1|1,m+1,R);
    use[k].tl=min(use[k<<1].tl,use[k<<1|1].tl);
    use[k].tr=max(use[k<<1].tr,use[k<<1|1].tr);
}
inline void findd(ll k,ll L,ll R,ll l,ll r)
{
    if(l<=L&&R<=r)
    {
        x_now=min(x_now,use[k].tl);
        y_now=max(y_now,use[k].tr);
        return;
    }
    ll m=(L+R)>>1;
    if(m>=l)
        findd(k<<1,L,m,l,r);
    if(m<r)
        findd(k<<1|1,m+1,R,l,r);
}
 
int main()
{
    //scanf("%lld",&n);
    n=read();
    for(re i=1;i<=n;i++)
    {
        x[i]=read();
        d[i]=read();
    }
    //    scanf("%lld%lld",&x[i],&d[i]);
    for(re i=1;i<=n;i++)
    {
        l[i]=lower_bound(x+1,x+i+1,x[i]-d[i])-x;
        r[i]=upper_bound(x+i+1,x+n+1,x[i]+d[i])-x-1;
    }
    build(1,1,n);
    for(register long long i=1;i<=n;i++)
    {
        xx=yy=x_now=y_now=i;
        findd(1,1,n,xx,yy);
        while(xx!=x_now||yy!=y_now)
        {
            xx=x_now;
            yy=y_now;
            findd(1,1,n,xx,yy);
        }
        ans=(ans+(y_now-x_now+1)*i%mo)%mo;
    }
    printf("%lld",ans%mo);
    return 0;
}


 
posted @ 2021-04-03 19:37  WindZR  阅读(305)  评论(0编辑  收藏  举报