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;
}
时间: 2024-10-08 06:37:44

bzoj5017: [Snoi2017]炸弹的相关文章

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

5017: [Snoi2017]炸弹 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 608  Solved: 190[Submit][Status][Discuss] Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi?Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? Inp

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

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

[LOJ#2255][BZOJ5017][Snoi2017]炸弹

试题描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi?Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢? 输入 第一行,一个数字 N,表示炸弹个数. 第 2-N+1行,每行 2 个数字,表示 Xi,Ri,保证 Xi 严格递增. N≤500000 ?10^18≤Xi≤10^18 0≤Ri≤2×10^18 输出 一个数字,表示Sigma(i*炸弹

【BZOJ-1218】激光炸弹 前缀和 + 枚举

1218: [HNOI2003]激光炸弹 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1778  Solved: 833[Submit][Status][Discuss] Description 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标.现在地图上有n(N<=10000)个目标,用整数Xi,Yi(其值在[0,5000])表示目标在地图上的位置,每个目标都有一个价值.激光炸弹的投放是通过卫星定位的,但其有一个缺点,就是其爆破

fork炸弹

:(){ :|:& };:                         # 著名的 fork炸弹,系统执行海量的进程,直到系统僵死 fork炸弹(fork bomb)在计算机领域中是一种利用系统调用fork(或其他等效的方式)进行的拒绝服务攻击.与病毒与蠕虫不同的是,fork炸弹没有传染性,而且fork炸弹会使对同时执行进程/程序数设限的系统无法执行新程序,对于不设限的系统则使之停止响应.以fork炸弹为代表的自我复制程序有时亦被称为wabbit. fork炸弹的概念:进程递归式派生(for

【吃炸弹的鸽子UVA10765-双联通模板】

·从前有一个鸽子Lence,它吃了一个炸弹,然后有人出了这道题. ·英文题,述大意:        给出一张连通无向图,求出:对于每个点,删去这个点(以及它相连的边以后)时,当前图中的连通块数量,这个值作为该点的Lence值.输出根据Lence值从大到小(相同时标号从小到大)的前m个点和它的Lence值. ·分析:       关于连通块问题,可以寻得三种方法:       ①嘎嘣脆算法(Gabow)②塔尔杨算法(Tarjan)③Kosaraju算法.        此处大米饼采用Tarjan算

cmu二进制炸弹

本篇文章参考了:http://www.cnblogs.com/remlostime/archive/2011/05/21/2052708.html大神的文章,有时候没思路了会来看一下,但是保证本文的每个阶段都是自己独立思考后总结写出来的. Phase_1 对于phase1,我们只要关注一下红色框两行的代码,分别是将内存0x8049678的处的字符串A和ebp+0x8处的字符串B作为参数来调用strings_not_equal子程序,那么这里的逻辑也很明了——要想知道要求我们输入的字符串,只要查看

BZOJ 1218: [HNOI2003]激光炸弹( 前缀和 + 枚举 )

虽然source写着dp , 而且很明显dp可以搞...但是数据不大 , 前缀和 + 枚举也水的过去..... ------------------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream&g

hdu 1072 有炸弹的迷宫

题意:在n×m的地图上,0表示墙,1表示空地,2表示人,3表示目的地,4表示有定时炸弹重启器.定时炸弹的时间是6,人走一步所需要的时间是1.每次可以上.下.左.右移动一格.当人走到4时如果炸弹的时间不是0,可以重新设定炸弹的时间为6.如果人走到3而炸弹的时间不为0时,成功走出.求人从2走到3的最短时间.这个题中每个结点都是可以重复访问的,但其实,炸弹重置点不要重复走,因为,走到炸弹重置点时时间就会被设置为最大时间,当重新返回时时间又设成最大,但此时已走的步数肯定增加了 Sample Input3