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

这道题我做了有半个月了...终于A了...
有图为证

一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案
首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以是由它能炸到的其他炸弹来炸到.也就是说具有拓扑性.(a->b,b->c==a->c)
所以我们首先有了一个想法:建反图,tarjan缩点,跑拓扑.
为什么建反图?因为i能炸到j,所以j能炸到的i就可以炸到了,所以建反图从j->i可以实现这一点.
但是每个炸弹能炸到的是一个区间,怎么搞呢?
线段树优化建边,每次log次建边.
//二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案
#include<bits/stdc++.h>
#define N 500005
#define INF 0x3f3f3f3f
#define p 1000000007
#define LL long long
#define lch k<<1
#define rch k<<1|1
#define xx puts("xuefnngh");
using namespace std;
int n,num_bian,num_stack,num_dfn,num_tarjan;
int ls[N<<],rs[N<<],tree[N],mx[N<<],mi[N<<],head[N<<],fm[N*],to[N*],nxt[N*];
int dfn[N<<],low[N<<],sta[N<<],in_sta[N<<],Mi[N<<],Mx[N<<],bel[N<<],in_deg[N<<];
LL dis[N],R[N];
void add(int x,int y){if(x==y)return;/*printf("%d %d\n",x,y);*/to[++num_bian]=y;fm[num_bian]=x;nxt[num_bian]=head[x];head[x]=num_bian;}
void Build(int k,int l,int r){
ls[k]=l;rs[k]=r;mi[k]=INF;
if(l==r)return (void) (tree[l]=k);
Build(lch,l,(l+r)/);Build(rch,(l+r)/+,r);
add(lch,k);add(rch,k);
}
void find(int k,int g,int L,int R){
if(ls[k]==rs[k])return (void)(mx[k]=R,mi[k]=L);
if(g<=rs[lch])find(lch,g,L,R);else find(rch,g,L,R);
mx[k]=max(mx[lch],mx[rch]);mi[k]=min(mi[lch],mi[rch]);
}
void connect(int k,int l,int r,int g){
if(ls[k]>=l&&rs[k]<=r) return (void) (add(k,g));
if(l<=rs[lch])connect(lch,l,r,g);
if(r>=ls[rch])connect(rch,l,r,g);
}
void tarjan(int x){
dfn[x]=low[x]=++num_dfn;in_sta[x]=;sta[++num_stack]=x;
for(int i=head[x];i;i=nxt[i])
if(!dfn[to[i]])
tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
else if(in_sta[to[i]])low[x]=min(low[x],dfn[to[i]]);
if(dfn[x]==low[x]){
int z;++num_tarjan;Mi[num_tarjan]=INF;
/*printf("huan:%d\n",num_tarjan);*/
do{
z=sta[num_stack--];
/*printf("%d ",z);*/
bel[z]=num_tarjan;
in_sta[z]=;
Mi[num_tarjan]=min(Mi[num_tarjan],mi[z]);
Mx[num_tarjan]=max(Mx[num_tarjan],mx[z]);
}while(z!=x);
/*puts("");
printf("%d %d\n",Mi[num_tarjan],Mx[num_tarjan]);*/
}
}
int que[N<<];
void top_sort(){
for(int i=;i<=num_tarjan;++i)if(!in_deg[i])que[++que[]]=i;
for(int i=;i<=que[];++i)
for(int j=head[que[i]];j;j=nxt[j]){
--in_deg[to[j]];
Mx[to[j]]=max(Mx[to[j]],Mx[que[i]]);Mi[to[j]]=min(Mi[to[j]],Mi[que[i]]);
if(!in_deg[to[j]])que[++que[]]=to[j];
}
}
int main(){
scanf("%d",&n);Build(,,n);
for(int i=;i<=n;++i)scanf("%lld%lld",&dis[i],&R[i]);
for(int i=;i<=n;++i){
int L=lower_bound(dis+,dis+n+,dis[i]-R[i])-dis;
int RR=upper_bound(dis+,dis+n+,dis[i]+R[i])-dis-;
/*printf("%d %d %d\n",i,L,RR);*/
connect(,L,RR,tree[i]);find(,i,L,RR);/*printf("333%d\n",tree[i]);*/
}
for(int i=;i<=tree[n];++i)if(!dfn[i])tarjan(i);
/*puts("xuueue");*/
int num_pre=num_bian;num_bian=;memset(head,,sizeof head);
for(int i=;i<=num_pre;++i)if(bel[fm[i]]!=bel[to[i]])add(bel[fm[i]],bel[to[i]]),in_deg[bel[to[i]]]++;
top_sort();
LL Ans=;for(int i=;i<=n;++i)(Ans+=(1ll*Mx[bel[tree[i]]]-Mi[bel[tree[i]]]+)*i%p+p)%=p/*,printf("%lld\n",Ans)*/;printf("%lld",Ans);
}
炸弹:线段树优化建边+tarjan缩点+建反边+跑拓扑的更多相关文章
- bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)
直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...
- 『炸弹 线段树优化建图 Tarjan』
炸弹(SNOI2017) Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸 时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi ...
- [SNOI2017]炸弹[线段树优化建图]
[SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...
- BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]
方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...
- [bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑
5017: [Snoi2017]炸弹 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 608 Solved: 190[Submit][Status][ ...
- 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)
题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...
随机推荐
- 阶段3 2.Spring_10.Spring中事务控制_1 基于XML的AOP实现事务控制
新建项目 首先把依赖复制进来 aop必须引入.aspectjweaver 复制src下的所有内容 复制到我们的新项目里面 factory文件夹删掉 删除后测试类必然就报错 配置文件 beanFacto ...
- 阶段3 2.Spring_06.Spring的新注解_7 spring整合junit问题分析
测试类重复代码的问题 这是之前的方式 运行findAll的方法,没有问题 测试人员不需要关心上面的方法,.应该关心的各个方法是否能够正常的运行 对于一个测试工程师,只要写完变量就可以测试了. 可以使用 ...
- 对docker一些认知
关于docker(应用容器引擎) docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化.容器是完全使用 ...
- 使用多个fixture和fixture直接互相调用
使用多个fixture 如果用例需要用到多个fixture的返回数据,fixture也可以return一个元组.list或字典,然后从里面取出对应数据. # test_fixture4.py impo ...
- CMake下,某些选项的后调整
编译安卓NDK库时,发现在R15的NDK编译出来的库,总是带了-g选项,导致附带调试,文件过大. 搜索一番后,结论是NDK的文件中有问题: https://github.com/android/ndk ...
- unieap 建库
create tablespace unieap datafile 'unieap.dbf' size 100M reuse autoextend on next 50M;1. 2.drop user ...
- 【github】git常用命令和node项目
这是之前在本地搞的一个小东西.因为之前电脑经常会很卡.后来发现任务管理器中多了两个不知名的进程:chromgpu.exe和flrefox.exe 乍一看以为和chrome和firefox两个浏览器有关 ...
- Linux vim文件编辑器使用
学习目标: 通过本实验熟练vim的使用. 步骤: 1.将用户家目录的ls结果重定向到vimfile.txt 2.查看rh124第403页实验要求,并完成 参考命令: 复制文件前,需要先建立文件,教材上 ...
- selenium.common.exceptions.WebDriverException: Message: ‘geckodriver’ executable needs to be in PATH
问题,找不到’geckodriver’ 的环境path,解决方案 下载geckodriver.exe 放到Firefox的安装目录下,如:(D:\火狐\Mozilla Firefox): 将火狐安装目 ...
- poj2407(欧拉函数模板题)
题目链接:https://vjudge.net/problem/POJ-2407 题意:给出n,求0..n-1中与n互质的数的个数. 思路:欧拉函数板子题,先根据唯一分解定理求出n的所有质因数p1,p ...