Solution

一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门

然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$

然后拓扑排序。 由于一次引爆的炸弹 一定是一个连续的区间内, 所以只需要记录左右边界, 并将左右边界转移给能到达它的联通块。

没写手工栈一直RE的我心里$mmp$啊。 为什么网上的题解都不写手工栈$QAQ$

Code

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rd read()
#define ll long long
using namespace std; const int N = ;
const int mod = 1e9 + ;
const ll inf = 3e18; int n, lscnt;
int head[N], tot;
int Head[N], Tot;
int low[N], dfn[N], dfstot;
int c[N], col;
ll minn[N], maxn[N], ls[N];
int st[N], tp;
bool vis[N], inq[N]; struct edge {
int nxt, to;
}e[N * ], E[N * ]; struct boom {
ll pos, r;
}bo[N]; ll read() {
ll X = , p = ; char c = getchar();
for (; c > '' || c < ''; c = getchar())
if (c == '-') p = -;
for (; c >= '' && c <= ''; c = getchar())
X = X * + c - '';
return X * p;
} void add(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
} void Add(int u, int v) {
E[++Tot].to = v;
E[Tot].nxt = Head[u];
Head[u] = Tot;
} namespace SegT {
#define mid ((l + r) >> 1)
int lc[N], rc[N], root, cnt; void build(int &p, int l, int r) {
if (l == r) {
p = l; return;
}
p = ++cnt;
build(lc[p], l, mid);
build(rc[p], mid + , r);
add(p, lc[p]); add(p, rc[p]);
} void update(int L, int R, int c, int l, int r, int x) {
if (L > R) return;
if (L <= l && r <= R) {
add(c, x); return;
}
if (mid >= L)
update(L, R, c, l,mid, lc[x]);
if (mid < R)
update(L, R, c, mid + , r, rc[x]);
}
}using namespace SegT; #define R register
int stx[N], sti[N], lv, stnt[N];
#define u stx[lv]
#define nt stnt[lv]
#define i sti[lv]
void tarjan(int x) {
lv = ; stx[] = x;
start:;
low[u] = dfn[u] = ++dfstot;
inq[u] = true; st[++tp] = u;
for (i = head[u]; i; i = e[i].nxt) {
nt = e[i].to;
if (!dfn[nt]) {
// tarjan(nt);
stx[lv + ] = nt;
lv++;
goto start;
end:;
low[u] = min(low[u], low[nt]);
}
else if (inq[nt]) low[u] = min(low[u], dfn[nt]);
}
if (low[u] == dfn[u]) {
col++;
for (; tp;) {
int z = st[tp--];
inq[z] = false;
if (z <= n)
maxn[col] = max(maxn[col], bo[z].pos + bo[z].r),
minn[col] = min(minn[col], bo[z].pos - bo[z].r);
c[z] = col;
if (z == u) break;
}
}
--lv;
if (lv) goto end;
}
#undef u
#undef nt
#undef i void dfs(int u) {
vis[u] = true;
for (R int i = Head[u]; i; i = E[i].nxt) {
int nt = E[i].to;
if (vis[nt] == false) dfs(nt);
minn[u] = min(minn[u], minn[nt]);
maxn[u] = max(maxn[u], maxn[nt]);
}
} int fdl(ll x) {
return lower_bound(ls + , ls + + lscnt, x) - ls;
} int fdr(ll x) {
int re = lower_bound(ls + , ls + + lscnt, x) - ls;
if (ls[re] == x) return re;
else return re - ;
} int main()
{
cnt = n = rd;
for (R int i = ; i <= n; ++i) {
bo[i].pos = rd; bo[i].r = rd;
ls[++lscnt] = bo[i].pos;
}
sort(ls + , ls + + lscnt);
lscnt = unique(ls + , ls + + lscnt) - ls - ;
build(root, , n);
for (int i = ; i <= n; ++i) {
int l = fdl(bo[i].pos - bo[i].r), r = fdr(bo[i].pos + bo[i].r), m = fdl(bo[i].pos);
update(l, m - , m, , n, root);
update(m + , r, m, , n, root);
}
for (int i = ; i < N; ++i)
maxn[i] = -inf, minn[i] = inf;
for (int i = ; i <= cnt; ++i)
if (!dfn[i]) tarjan(i);
for (int u = ; u <= cnt; ++u)
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (c[u] == c[v])
continue;
Add(c[u], c[v]);
}
for (int i = ; i <= col; ++i) dfs(i);
ll ans = ;
for (int i = ; i <= n; ++i) {
int l = fdl(minn[c[i]]), r = fdr(maxn[c[i]]);
(ans += 1LL * i * (r - l + ) % mod) %= mod;
}
printf("%lld\n", ans);
}

BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan的更多相关文章

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

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

  2. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

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

  3. [SNOI2017]炸弹[线段树优化建图]

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

  4. bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)

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

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

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

  6. BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]

    方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...

  7. 炸弹:线段树优化建边+tarjan缩点+建反边+跑拓扑

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

  8. 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)

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

  9. BZOJ5017 炸弹(线段树优化建图+Tarjan+拓扑)

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

随机推荐

  1. 深入分析JavaWeb Item2 -- Tomcat服务器学习和使用

    https://segmentfault.com/a/1190000004095363 一.Tomcat服务器端口的配置 Tomcat的所有配置都放在conf文件夹之中,里面的server.xml文件 ...

  2. 简述Ajax原理及实现步骤

    简述Ajax原理及实现步骤 1.Ajax简介 概念 Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML). 现在允许浏览器与务器通信 ...

  3. 如何从 VSS 迁移到Team Foundation Server

    TFS 2012自带了vss upgrade wizard工具, 在Team Foundation Server管理控制台左侧的最后一个菜单其他工具和组件中,选择Visual SourceSafe升级 ...

  4. crossdomain.xml配置不当的利用和解决办法

    00x1: 今天在无聊的日站中发现了一个flash小站,点进crossdomain.xml一看,震惊 本屌看到这个*就发觉事情不对 百度一下,这是一个老洞,配置不当能引起各种问题就算能远程加载恶意的s ...

  5. 0003 - 基于xml的Spring Bean 的创建过程

    一.目录 前言 创建 Bean 容器 加载 Bean 定义 创建 Bean Spring Bean 创建过程中的设计模式 总结 二.前言 2.1 Spring 使用配置 ApplicationCont ...

  6. μC/Probe尝鲜

    μC/Probe 1.添加文件 2.配置probe_com_cfg.h 2.1.选择接口 #define PROBE_COM_CFG_RS232_EN DEF_ENABLED /* Configure ...

  7. 常用命令npm,gulp, node

    npm常用命令: 检查npm模块的安装情况:(以常用模块 grunt为例说明) 1) 检查是否全局安装了模块Grunt: $npm list -g grunt 2) 列出所有已经全局安装的模块:$np ...

  8. oracle自定义函数返回结果集

    首先要弄两个type,不知道什么鬼: 1. create or replace type obj_table as object ( id ), name ), ) ) 2. create or re ...

  9. !!字体图标(iconfont、Fontello 、雪碧图生成工具。Glyphicons、fontawesome 等)。 图片压缩

    http://www.iconfont.cn/  阿里巴巴矢量图标库 iconfont http://fontawesome.io fontawesome图标 http://www.bootcss.c ...

  10. 修改java在进程中的映像名

    java小程序用java -jar xxx.jar  启动的进程映像名都是java.exe. 如果启动多个小程序就不好区分,导致监控程序无法定位到具体需要守护的小程序上. 解决办法: 在java安装目 ...