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$ 然后拓扑排序. ...
随机推荐
- Redis相关知识
Redis 存储的五种 字符串类型:string 一个String类型的value最大可以存储512M String是最常用的一种数据类型,普通的key/value存储. 散列类型: hash 键值 ...
- app直播原理
之前写的一系列文章或者小经验一直没有时间去整理放在博客上,今天整理出来,之前是写在作业部落,语法是markdown,点击链接浏览,仅供参考,希望对你有帮助. https://www.zybuluo.c ...
- 如何设计一个优秀的API
如何设计一个优秀的API - 文章 - 伯乐在线 http://blog.jobbole.com/42317/ 如何设计一个优秀的API - 标点符 https://www.biaodianfu.co ...
- ul li menu
第一步:建立一个无序列表我们先建立一个无序列表,来建立菜单的结构.代码是: <ul><li><a href="1">首页</a>&l ...
- Deep Learning 36:python中的一些函数
1.map(function, sequence[, sequence, ...])函数:返回一个list作用:map的作用是以参数序列中的每一个元素调用function函数,返回包含每次functi ...
- React通用后台管理系统
react-admin 部分采用了antd,相关功能较全,添加了较多的组件模块.star 664 GitHub:https://github.com/yezihaohao/react-admin 在线 ...
- 验证外部系统是否成功调用SAP RFC的方法有几种?
- swt进度条 线程
import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import java.util.Rando ...
- mysql字符串的常用函数(截取和拼接)
#截取字符串(先正序取2个,再倒序取1个)SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('aaa-gg-cc-dd','-',2),'-',-1) #获取子表某个字段的 ...
- html5--6-50 动画效果-变形
html5--6-50 动画效果-变形 实例 学习要点 掌握2D变形动画 了解3D变形动画 transform:2D变形: 通过 CSS3 转换,我们能够对元素进行移动.缩放.转动.拉长或拉伸.转换方 ...