『炸弹 线段树优化建图 Tarjan』

时间:2022-12-22 08:21:22

<更新提示>

<第一次更新>


<正文>

炸弹(SNOI2017)

Description

在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸 时,如果另一个炸弹所在位置 Xj 满足:

Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆。 现在,请你帮忙计算一下,先把第 i 个炸弹引爆,将引爆多少个炸弹呢?

Input Format

第一行,一个数字 N,表示炸弹个数。 第 2∼N+1行,每行 2 个数字,表示 Xi,Ri,保证 Xi 严格递增。

N≤500000

−10 ^18≤Xi≤10 ^18

0≤Ri≤2×10 ^18

Output Format

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

Sample Input

4
1 1
5 1
6 5
15 15

Sample Output

32

解析

很自然我们可以将问题转化为图论的模型:每个炸弹当做一个点,向可以连环引爆的其他点连边,然后一个点的答案就是这个点出发\(dfs\)可以遍历到的所有点。

直接连边的话建图就会超时,边数的\(n^2\)的,不难发现每一个点要连边的点处于连续的一段区间中,于是想到线段树优化建图。

什么是线段树优化建图?就是把线段树用邻接表显式的建出来,然后对于一个区间内的连续若干个点的连边,就可以利用线段树区间划分的方式,向不超过\(log_2(r-l+1)\)个线段树节点连边,以达到向这当中所有点连边的目的。

建完图后,我们又发现对每一个点都\(dfs\)会超时,于是想到将互相可达的点先处理掉,也就是\(SCC\)缩点,然后在剩下的\(DAG\)上,反图\(dp\)即可统计每一个点的答案。在这当中,我们需要维护一下每个点可达区间的最小左端点和最大右端点即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 500020 , Mod = 1000000007;
struct edge { int ver,next; } e1[N*25],e2[N*25];
struct SegmentTree
{
int l,r,id,re;
#define l(p) ver[p].l
#define r(p) ver[p].r
#define id(p) ver[p].id
#define re(p) ver[p].re
}ver[N<<2];
int n,t1,t2,Head1[N*2],Head2[N*2],indeg[N*2],tot;
int dfn[N*2],low[N*2],ins[N*2],st[N*2],c[N*2],top,num,cnt;
int Min[N*2],Max[N*2];
long long x[N],r[N],ans;
inline void insert1(int x,int y)
{
e1[++t1] = (edge){y,Head1[x]} , Head1[x] = t1;
}
inline void insert2(int x,int y)
{
e2[++t2] = (edge){y,Head2[x]} , Head2[x] = t2;
}
inline void chmin(int &a,int b) { a = min( a , b ); }
inline void chmax(int &a,int b) { a = max( a , b ); }
inline void input(void)
{
scanf("%d",&n);
for ( int i = 1; i <= n; i++ )
scanf("%lld%lld",&x[i],&r[i]);
}
inline void BuildTree(int p,int l,int r)
{
l(p) = l , r(p) = r;
if ( l == r ) { id(p) = l , re(l) = p; return; }
id(p) = ++tot , re(tot) = p;
int mid = l + r >> 1;
BuildTree( p<<1 , l , mid );
BuildTree( p<<1|1 , mid+1 , r );
insert1( id(p) , id(p<<1) );
insert1( id(p) , id(p<<1|1) );
}
inline void connect(int p,int l,int r,int x)
{
if ( l <= l(p) && r >= r(p) ) return insert1( x , id(p) );
int mid = l(p) + r(p) >> 1;
if ( l <= mid ) connect( p<<1 , l , r , x );
if ( r > mid ) connect( p<<1|1 , l , r , x );
}
inline void Tarjan(int x)
{
dfn[x] = low[x] = ++num;
st[++top] = x , ins[x] = true;
for ( int i = Head1[x]; i; i = e1[i].next )
{
int y = e1[i].ver;
if ( !dfn[y] )
{
Tarjan( y );
low[x] = min( low[x] , low[y] );
}
else if ( ins[y] )
low[x] = min( low[x] , dfn[y] );
}
if ( dfn[x] == low[x] )
{
++cnt; int y;
do
{
y = st[top--] , ins[y] = false;
c[y] = cnt;
chmin( Min[cnt] , l(re(y)) );
chmax( Max[cnt] , r(re(y)) );
}
while ( x != y );
}
}
inline void Topsort(void)
{
queue < int > q;
for ( int i = 1; i <= tot; i++ )
if ( !indeg[i] ) q.push(i);
while ( !q.empty() )
{
int x = q.front(); q.pop();
for ( int i = Head2[x]; i; i = e2[i].next )
{
int y = e2[i].ver;
chmin( Min[y] , Min[x] );
chmax( Max[y] , Max[x] );
if ( ! -- indeg[y] ) q.push( y );
}
}
}
inline void BuildGraph(void)
{
for ( int i = 1; i <= n; i++ )
{
int L = lower_bound( x+1 , x+i+1 , x[i] - r[i] ) - x;
int R = upper_bound( x+i+1 , x+n+1 , x[i] + r[i] ) - x - 1;
connect( 1 , L , R , i );
}
}
inline void rebuild(void)
{
for ( int x = 1; x <= tot; x++ )
{
for ( int i = Head1[x]; i; i = e1[i].next )
{
int y = e1[i].ver;
if ( c[x] != c[y] )
insert2( c[y] , c[x] ) , indeg[c[x]]++;
}
}
}
inline void solve(void)
{
for ( int i = 1; i <= n; i++ )
ans = ( ans + 1LL * i * ( Max[c[i]] - Min[c[i]] + 1 ) % Mod ) % Mod;
}
int main(void)
{
input();
tot = n , BuildTree( 1 , 1 , n );
BuildGraph();
memset( Min , 0x3f , sizeof Min );
memset( Max , 0x00 , sizeof Max );
for ( int i = 1; i <= tot; i++ )
if ( !dfn[i] ) Tarjan( i );
rebuild();
Topsort();
solve();
printf("%lld\n",ans);
return 0;
}

<后记>

『炸弹 线段树优化建图 Tarjan』的更多相关文章

  1. 【bzoj5017】&lbrack;Snoi2017&rsqb;炸弹 线段树优化建图&plus;Tarjan&plus;拓扑排序

    题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆.  现在 ...

  2. BZOJ5017 &lbrack;SNOI2017&rsqb;炸弹 - 线段树优化建图&plus;Tarjan

    Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...

  3. bzoj5017 &lbrack;Snoi2017&rsqb;炸弹 &lpar;线段树优化建图&plus;&rpar;tarjan 缩点&plus;拓扑排序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...

  4. bzoj5017 炸弹 &lpar;线段树优化建图&plus;tarjan&plus;拓扑序dp&rpar;

    直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...

  5. 炸弹&colon;线段树优化建边&plus;tarjan缩点&plus;建反边&plus;跑拓扑

    这道题我做了有半个月了...终于A了... 有图为证 一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案 首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以 ...

  6. 【2019&period;7&period;26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图&plus;Tarjan缩点&plus;拓扑排序)

    题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...

  7. &lbrack;SNOI2017&rsqb;炸弹&lbrack;线段树优化建图&rsqb;

    [SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...

  8. BZOJ5017 炸弹(线段树优化建图&plus;Tarjan&plus;拓扑)

    Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被 ...

  9. Libre OJ 2255 (线段树优化建图&plus;Tarjan缩点&plus;DP)

    题面 传送门 分析 主体思路:若x能引爆y,从x向y连一条有向边,最后的答案就是从x出发能够到达的点的个数 首先我们发现一个炸弹可以波及到的范围一定是坐标轴上的一段连续区间 我们可以用二分查找求出炸弹 ...

随机推荐

  1. Linux之源码包安装软件

    安装准备      安装c语言编辑器 gcc      压缩包  node-v6.2.0-linux-x64.tar.gz   源码包保存位置  /usr/local/src/ 源码包安装位置 /us ...

  2. Text Template Transformation Toolkit

    Text Template Transformation Toolkit       1.且算简介         笔者以一个英文字母和一个数字取了一个简单的名字.名唤"T4"(名 ...

  3. Intellij idea 2018的注册方式

    激活方式:License Server 第一步: 将地址 http://active.chinapyg.com/ 或者 http://idea.toocruel.net 任意一个复制到License ...

  4. php向mariaDB插入数据时乱码问题解决 --- mysqli&lowbar;set&lowbar;charset(设置默认字符编码)

    参考文章: https://www.w3schools.com/php/func_mysqli_set_charset.asp http://php.net/manual/zh/mysqli.set- ...

  5. upstream timed out &lpar;110&colon; Connection timed out&rpar; while reading response header from upstream

    Nginx报错日志有如下内容: upstream timed out (110: Connection timed out) while reading response header from up ...

  6. SpringCloud请求响应数据转换(二)

    上篇文章记录了从后端接口返回数据经过切面和消息转换器处理后返回给前端的过程.接下来,记录从请求发出后到后端接口调用过的过程. web请求处理流程 源码分析 ApplicationFilterChain ...

  7. 使用 extract-text-webpack-plugin 报错:Error&colon; Chunk&period;entry was removed&period; Use hasRuntime&lpar;&rpar;

    问题:使用 extract-text-webpack-plugin 报错:Error: Chunk.entry was removed. Use hasRuntime() 解决:先运行npm unin ...

  8. mysql Date查询当天、本周,本月,上一个月的数据

      出自:http://www.cnblogs.com/benefitworld/p/5832897.html 今天 select * from 表名 where to_days(时间字段名) = t ...

  9. 未能加载文件或程序集&OpenCurlyDoubleQuote;NPOI”或它的某一个依赖项

    自己遇到过得一个很麻瓜很耽误时间的bug,也请教了一些大神嫩是没找到解决方法 下面分享下问题和解决方法 做的是一个下载功能,本地是没问题IIS站点导出EXCEL的时候出错 我这边看不到错误信息,只能一 ...

  10. Spring MVC接受参数的注解

    一.Request请求发出后,Headler Method是如何接收处理数据的? Headler Method绑定常用的参数注解,根据处理request的不同部分分为四类: A.处理 Request ...