题面

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]炸弹的更多相关文章

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

    5017: [Snoi2017]炸弹 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 608  Solved: 190[Submit][Status][ ...

  2. [LOJ#2255][BZOJ5017][Snoi2017]炸弹

    [LOJ#2255][BZOJ5017][Snoi2017]炸弹 试题描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: ...

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

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

  4. bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)

    https://www.lydsy.com/JudgeOnline/problem.php?id=5017 暴力: 对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹 如果能,由这个炸弹向引爆 ...

  5. bzoj 5017 炸弹

    题目大意: 直线上有n个炸弹有坐标x和半径r 当一个炸弹被引爆时 若有炸弹的坐标在该炸弹坐标+-r范围内则另一个炸弹也被引爆 求先引爆每一个炸弹最终会引爆多少炸弹 思路: 可以想到n平方连边然后tar ...

  6. BZOJ5017题解SNOI2017炸弹--玄学递推

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5017 分析 老师讲课谈到了这道题,课上想出了个连边建图然后乱搞的操作,被老师钦定的递推方 ...

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

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

  8. [SNOI2017]炸弹

    嘟嘟嘟 这题有一些别的瞎搞神奇做法,而且复杂度似乎更优,不过我为了练线段树,就乖乖的官方正解了. 做法就是线段树优化建图+强连通分量缩点+DAGdp. 如果一个炸弹\(i\)能引爆另一个炸弹\(j\) ...

  9. BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan

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

随机推荐

  1. openssl 再爆惊天漏洞及紧急修复指南

    openssl 又摊上大事了,2014年6月5日,SSL/TLS Man-in-the-Middle Vulnerability 该漏洞使得攻击者能够拦截恶意中间节点加密和解密数据.同一时候强迫使用弱 ...

  2. (testng多个class文件执行时混乱,不是等一个class内的所有methods执行完再去执行下一个class内的内容)问题的解决

    问题描述如下: We use TestNG and Selenium WebDriver to test our web application. Now our problem is that we ...

  3. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

  4. sanic官方文档解析之下载和Configuration

    1,sanic框架是做什么的? sanic的官方网址:https://sanic.readthedocs.io/en/latest/ sanic框架是一个类似于flask框架的在Python3.5以上 ...

  5. LiberOJ#6178. 「美团 CodeM 初赛 Round B」景区路线规划 概率DP

    题意 游乐园被描述成一张 n 个点,m 条边的无向图(无重边,无自环).每个点代表一个娱乐项目,第 i 个娱乐项目需要耗费 ci 分钟的时间,会让小 y 和妹子的开心度分别增加 h1i ,h2i ,他 ...

  6. linux下的文件和文件夹的权限问题

    1 文件和文件夹的权限 文件和文件夹的权限设置的根本目的是控制人对它们的访问. 2 用户分类 本文件的拥有者.本文件所属的grou.其它用户. 3 也就是说 在读写文件或者文件夹时,要看看自己是属于哪 ...

  7. poj 1821 Fence(单调队列优化DP)

    poj 1821 Fence \(solution:\) 这道题因为每一个粉刷的人都有一块"必刷的木板",所以可以预见我们的最终方案里的粉刷匠一定是按其必刷的木板的顺序排列的.这就 ...

  8. codeforces 690C2 C2. Brain Network (medium)(bfs+树的直径)

    题目链接: C2. Brain Network (medium) time limit per test 2 seconds memory limit per test 256 megabytes i ...

  9. iOS成员变量、实例变量、属性变量三者的联系与区别

    一.类Class中的属性property 在ios第一版中: 我们为输出口同时声明了属性和底层实例变量,那时,属性是oc语言的一个新的机制,并且要求你必须声明与之对应的实例变量,例如: 注意:(这个是 ...

  10. [BZOJ 3697] 采药人的路径

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3697 [算法] 首先 , 将黑色的边变成1 ,白色的边变成-1 那么 , 问题就转化 ...