bzoj 5017 [Snoi2017]炸弹
题面
https://www.lydsy.com/JudgeOnline/problem.php?id=5017
题解
如果数据范围小一点那么就缩点 然后跑一个基础的DAG上的dp就好了
但是边数是$O(n^2)$的 所以就会炸
然后发现题目的特殊性
每一个点连向的点是连续的 换言之就是每个点和一个连续的段连上了一条边
那么我们把段拆开 用类似线段树的做法拆成log个小段 然后把这个点与这些小段连边即可
记得把每个段向它的儿子连上边
这样点数和边数都是$O(n \log n)$ 就可以了
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll; ll read(){
ll x=,f=;char c=getchar();
while(c<'' || c>''){if(c=='-')f=-;c=getchar();}
while(c>='' && c<=''){x=x*+c-'';c=getchar();}
return x*f;
} const int mod=1e9+;
const int maxn=;
int n,nwn;
ll pos[maxn],rad[maxn];
struct Node{
int l,r;
} tr[maxn*]; int dy[maxn]; inline bool pd(int a,int b){
return abs(pos[a]-pos[b])<=rad[a];
} int head[maxn*],nxt[maxn*],to[maxn*],cnt;
int rhead[maxn*],rnxt[maxn*],rto[maxn*],rcnt; inline void add_edge(int a,int b){
to[++cnt]=b;
nxt[cnt]=head[a];
head[a]=cnt;
rto[++rcnt]=a;
rnxt[rcnt]=rhead[b];
rhead[b]=rcnt;
} void build(int i,int l,int r){
tr[i].l=l,tr[i].r=r;
nwn=max(nwn,i);
if(l==r){
dy[l]=i;return;
}
int md=(l+r)>>;
build(i*,l,md);
build(i*+,md+,r);
add_edge(i,i*);
add_edge(i,i*+);
} inline void work(int ind,int i,int l,int r){
if(tr[i].l>r || tr[i].r<l) return;
if(tr[i].l>=l && tr[i].r<=r){
add_edge(dy[ind],i);
return;
}
work(ind,i*,l,r);
work(ind,i*+,l,r);
} int vis[maxn*];
int seq[maxn*],tot;
int col; void dfs1(int nw){
vis[nw]=;
for(int i=rhead[nw];i;i=rnxt[i]){
int v=rto[i];
if(vis[v]) continue;
dfs1(v);
}
seq[++tot]=nw;
} void dfs2(int nw){
vis[nw]=col;
for(int i=head[nw];i;i=nxt[i]){
int v=to[i];
if(vis[v]) continue;
dfs2(v);
}
} int sz[maxn*];
int ans[maxn*];
bool vis2[maxn*]; void dfs3(int nw){
if(ans[vis[nw]]==) ans[vis[nw]]=sz[vis[nw]];
vis2[nw]=;
for(int i=head[nw];i;i=nxt[i]){
int v=to[i];
if(vis2[v]) continue;
dfs3(v);
if(vis[v]!=vis[nw])
ans[vis[nw]]+=ans[vis[v]];
}
} int main(){
#ifdef LZT
freopen("in","r",stdin);
#endif
n=read();
build(,,n);
for(int i=;i<=n;i++)
pos[i]=read(),rad[i]=read();
int l,r;
for(int i=;i<=n;i++){
int L=,R=i;
while(L<=R){
int md=(L+R)>>;
if(pos[i]-pos[md]>rad[i]) L=md+;
else R=md-,l=md;
}
L=i,R=n;
while(L<=R){
int md=(L+R)>>;
if(pos[md]-pos[i]>rad[i]) R=md-;
else L=md+,r=md;
}
work(i,,l,r);
} for(int i=;i<=nwn;i++){
if(tr[i].l==) continue;
if(!vis[i]) dfs1(i);
}
memset(vis,,sizeof(vis)); for(int i=tot;i>=;i--)
if(!vis[seq[i]]) ++col,dfs2(seq[i]); for(int i=;i<=nwn;i++) if(tr[i].l && tr[i].l==tr[i].r) sz[vis[i]]++;
dfs3(); ll res=;
for(int i=;i<=nwn;i++){
if(tr[i].l<tr[i].r) continue;
res+=tr[i].l*1ll*ans[vis[i]]%mod;
res%=mod;
}
printf("%lld\n",res); return ;
} /*
4
1 1
5 1
6 5
15 15
*/
Review
动机?
首先缩点+dp是显然的
然后我就没有想到怎么优化
其实也不难想啊 就是要把连续的一段点转化成几个点 也就是区间->几个点 那么就上线段树嘛
然后写的时候注意总点数的处理
按照我的线段树写法 一棵树中 最小编号到最大编号之间不连续 也就是有一些编号不对应任何点
这样在遍历所有点的时候要判断一下当前编号是否存在
bzoj 5017 [Snoi2017]炸弹的更多相关文章
- [bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑
5017: [Snoi2017]炸弹 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 608 Solved: 190[Submit][Status][ ...
- [LOJ#2255][BZOJ5017][Snoi2017]炸弹
[LOJ#2255][BZOJ5017][Snoi2017]炸弹 试题描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: ...
- [SNOI2017]炸弹[线段树优化建图]
[SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...
- bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)
https://www.lydsy.com/JudgeOnline/problem.php?id=5017 暴力: 对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹 如果能,由这个炸弹向引爆 ...
- bzoj 5017 炸弹
题目大意: 直线上有n个炸弹有坐标x和半径r 当一个炸弹被引爆时 若有炸弹的坐标在该炸弹坐标+-r范围内则另一个炸弹也被引爆 求先引爆每一个炸弹最终会引爆多少炸弹 思路: 可以想到n平方连边然后tar ...
- BZOJ5017题解SNOI2017炸弹--玄学递推
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5017 分析 老师讲课谈到了这道题,课上想出了个连边建图然后乱搞的操作,被老师钦定的递推方 ...
- bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...
- [SNOI2017]炸弹
嘟嘟嘟 这题有一些别的瞎搞神奇做法,而且复杂度似乎更优,不过我为了练线段树,就乖乖的官方正解了. 做法就是线段树优化建图+强连通分量缩点+DAGdp. 如果一个炸弹\(i\)能引爆另一个炸弹\(j\) ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
随机推荐
- Effective C++ 条款42
本节条款我们讨论一下class 关键字和typename关键字的不同以及对于模板函数(template function)的影响. 例如以下代码: template<class T> T ...
- 备忘录模式-Memento
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态. 备忘录模式结构图: 何时使用备忘录模式: Memento模式比适合 ...
- CodeForces 24D Broken robot(期望+高斯消元)
CodeForces 24D Broken robot 大致题意:你有一个n行m列的矩形板,有一个机器人在开始在第i行第j列,它每一步会随机从可以选择的方案里任选一个(向下走一格,向左走一格,向右走一 ...
- (30)java web的hibernate使用-c3p0连接池配置
hibernate支持c3p0连接池 需要导入c3p0的jar包 <!-- 配置连接驱动管理类 --> <property name="hibernate.connecti ...
- Vijos P1389婚礼上的小杉
背景 小杉的幻想来到了经典日剧<求婚大作战>的场景里……他正在婚礼上看幻灯片,一边看着可爱的新娘长泽雅美,一边想,如果能再来一次就好了(-.-干嘛幻想这么郁闷的场景……). 小杉身为新一代 ...
- 用 nodejs 写一个命令行工具 :创建 react 组件的命令行工具
用 nodejs 写一个命令行工具 :创建 react 组件的命令行工具 前言 上周,同事抱怨说 react 怎么不能像 angular 那样,使用命令行工具来生成一个组件.对呀,平时工作时,想要创建 ...
- KMP 、扩展KMP、Manacher算法 总结
一. KMP 1 找字符串x是否存在于y串中,或者存在了几次 HDU1711 Number Sequence HDU1686 Oulipo HDU2087 剪花布条 2.求多个字符串的最长公共子串 P ...
- 利用JS判断当前来路域名并跳转到指定页面
某网站绑定了多个域名,默认情况下访问这些域名的时候是指向网站的首页,也就是访问不同域名时看到的页面是一样的,现在需要访问不同域名时显示不同页面. 一般情况下,可以用子站绑定域名的方法来实现,访问不同的 ...
- JavaScript Map对象的实现
1. [代码]js代码 /* * MAP对象,实现MAP功能 * * 接口: * size() 获取MAP元素个数 * isEmpty() 判断MAP是否为空 * clear() ...
- 一步一步学Silverlight 2系列(31):图形图像综合实例—实现水中倒影效果
概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, ...