bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=5017
题解
这个题目方法挺多的。
线段树优化建图
线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图。
这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点。
但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点。
时间复杂度 \(O(n\log n)\),空间复杂度 \(O(n\log n)\)。
一般的建图
可以发现在一个点可以炸到的炸弹中,真正会对最终答案的左右端点有贡献的只有这些炸弹里面左端点最小的和右端点最大的炸弹。
直接对这两个炸弹建边就可以了,然后和上面一样,先 tarjan 缩点,然后在 DAG 上跑出来左右端点。
但是因为想要确定左右端点对应的位置,所以这个 \(log\) 还是没有办法去掉。
时间复杂度 \(O(n\log n)\),空间复杂度 \(O(n)\)。
神仙的线性递推做法
https://www.cnblogs.com/saigyouji-yuyuko/p/11771364.html
丢个链接跑路。
我不会,好像很神仙的样子。
听说是时空都是线性的哦。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
typedef long long ll; typedef unsigned long long ull; //typedef std::pair<int, int> pii;
template<typename I> inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 500000 + 7;
const int M = 500000 * 2 + 7;
const int P = 1e9 + 7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int LOG = 19;
typedef std::pair<ll, int> pii;
int n, m, sccno, dfc, tp;
int dfn[N], low[N], scc[N], s[N];
std::vector<int> v[N];
ll a[N], r[N], dpl[N], dpr[N];
pii minl[N][LOG], maxr[N][LOG];
struct Edge { int to, ne; } g[M]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }
inline void dfs(int x) {
dfn[x] = low[x] = ++dfc, s[++tp] = x;
for fec(i, x, y) if (!dfn[y]) dfs(y), smin(low[x], low[y]);
else if (!scc[y]) smin(low[x], dfn[y]);
if (low[x] == dfn[x]) {
++sccno;
dpl[sccno] = INF, dpr[sccno] = -INF;
while (1) {
int y = s[tp--];
scc[y] = sccno, smax(dpr[scc[y]], a[y] + r[y]), smin(dpl[scc[y]], a[y] - r[y]);
v[scc[y]].pb(y);
if (x == y) break;
}
}
}
inline void tarjan() {
for (int i = 1; i <= n; ++i)
if (!dfn[i]) dfs(i);
}
inline void rmq_init() {
for (int i = 1; i <= n; ++i) minl[i][0] = pii(a[i] - r[i], i), maxr[i][0] = pii(a[i] + r[i], i);
for (int j = 1; (1 << j) <= n; ++j)
for (int i = 1; i + (1 << j) - 1 <= n; ++i)
minl[i][j] = std::min(minl[i][j - 1], minl[i + (1 << (j - 1))][j - 1]),
maxr[i][j] = std::max(maxr[i][j - 1], maxr[i + (1 << (j - 1))][j - 1]);
}
inline pii qmin(int l, int r) {
int k = std::__lg(r - l + 1);
return std::min(minl[l][k], minl[r - (1 << k) + 1][k]);
}
inline pii qmax(int l, int r) {
int k = std::__lg(r - l + 1);
return std::max(maxr[l][k], maxr[r - (1 << k) + 1][k]);
}
inline void work() {
rmq_init();
for (int i = 1; i <= n; ++i) {
int pl = std::lower_bound(a + 1, a + n + 1, a[i] - r[i]) - a,
pr = std::upper_bound(a + 1, a + n + 1, a[i] + r[i]) - a - 1;
addedge(i, qmin(pl, pr).se);
addedge(i, qmax(pl, pr).se);
}
tarjan();
for (int i = 1; i <= sccno; ++i) {
int len = v[i].size();
for (int j = 0; j < len; ++j) {
int x = v[i][j];
for fec(iii, x, y) smin(dpl[i], dpl[scc[y]]), smax(dpr[i], dpr[scc[y]]), assert(scc[y] <= i);
}
}
ll ans = 0;
for (int i = 1; i <= n; ++i) {
int pl = std::lower_bound(a + 1, a + n + 1, dpl[scc[i]]) - a,
pr = std::upper_bound(a + 1, a + n + 1, dpr[scc[i]]) - a - 1;
ans += (ll)i * (pr - pl + 1);
}
printf("%lld\n", ans % P);
}
inline void init() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]), read(r[i]);
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序的更多相关文章
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)
题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]
方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...
- 炸弹:线段树优化建边+tarjan缩点+建反边+跑拓扑
这道题我做了有半个月了...终于A了... 有图为证 一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案 首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以 ...
- [SNOI2017]炸弹[线段树优化建图]
[SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...
- bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)
直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...
- 『炸弹 线段树优化建图 Tarjan』
炸弹(SNOI2017) Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸 时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi ...
- Libre OJ 2255 (线段树优化建图+Tarjan缩点+DP)
题面 传送门 分析 主体思路:若x能引爆y,从x向y连一条有向边,最后的答案就是从x出发能够到达的点的个数 首先我们发现一个炸弹可以波及到的范围一定是坐标轴上的一段连续区间 我们可以用二分查找求出炸弹 ...
随机推荐
- redis--迁库操作
如果碰到redis库要迁移(之前的redis用作他用)或者备份用,就需要操作redis迁移 import redis def qianyi(k=None,v=None,name=None): r1 = ...
- day64—ajax技术学习笔记
转行学开发,代码100天——2018-05-19 Ajax技术学习笔记 AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML).AJA ...
- App测试工具选择
一.功能测试自动化 a) 轻量接口自动化测试: jmeter, b) APP UI层面的自动化 android:UI Automator Viewer,Android Junit,Instrument ...
- oracle ogg--ogg搭建过程中遇到的错误及处理
1 PRVF-0002 : Could not retrieve local nodename---# Begin Stacktrace #---------------------------ID: ...
- linux 学习笔记一
Linux 学习笔记一 计算机 主要分为五个部分:控制器,运算器,存储器,输入设备,输出设备. 操作系统 操作系统就是针对硬件编写的程序,同时提供硬件接口调用的接口.操作系统需要处理如管理与配置内存. ...
- 别把&和nohup混为一谈, 根本不是同一个东西好不好 ------ 聊聊./a.out & , nohut ./a.out , nohup ./a.out &的区别
在第一家公司工作的时候, 我认识了&,在第二家公司工作的时候, 我认识了nohup, 这就是渊源. 随后, 我就一直糊涂用他们, 但并不懂这两个东西. 网上很多地方是乱扯, 瞎复制, 为什 ...
- 定制属于你自己的ViewEngine(一套逻辑多套UI)
ASP.NET MVC出来这么久了,心中却又很多的疑惑:为什么所有的View都要放在Views目录下? 为什么Shared文件夹下面的页面可以被共享? 为什么Page既可以是*.cshtml,也可以是 ...
- IntelliJ IDEA 2019.1.1 maven框架web.xml中web-app版本过低导致不能正常使用EL表达式的解决方案
1.软件版本 IDEA版本:IntelliJ IDEA 2019.1.1 maven版本:apache-maven-3.6.1 Tomcat版本:tomcat-8.5 2.问题描述 IDEA使用如下 ...
- Git配置用户名、邮箱
当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址. 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改. 否则,用户名会显示为unkno ...
- Python基础语法之字典
1 字典基础 1.1 字典是无序的对象的集合,通过键来存取,字典的键只能是不可变类型. 1.3 字典的长度可变,异构,任意嵌套. 1.2 python中不可变数据类型包括:数值类型,字符串和元组. 2 ...