zoukankan      html  css  js  c++  java
  • 炸弹

    题目描述

    在一条直线上有 $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;
    }


     
  • 相关阅读:
    数据结构之队列
    设计模式之策略模式的使用
    搭建一个高可用的redis环境
    Linux遗忘命令
    重温几种排序算法之希尔排序、归并排序、快速排序
    HashMap的简单实现
    Java GC基础
    2016年年终总结
    Shell 备忘录
    Openstack Grizzily 单节点测试机安装( All In One CentOS/RHEL)
  • 原文地址:https://www.cnblogs.com/WindZR/p/14614614.html
Copyright © 2011-2022 走看看