炸弹:线段树优化建边+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缩点+拓扑排序)
题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...
随机推荐
- oracle 一张表插入另外一张表 存储过程
----创建存储过程 create or replace procedure inserttest as cursor cs is select id, name, cla, addr, phone, ...
- java:Springmvc框架3(Validator)
1.springmvcValidator: web.xml: <?xml version="1.0" encoding="UTF-8"?> < ...
- Prometheus告警模型分析
Prometheus作为时下最为流行的开源监控系统,其庞大的生态体系:包括针对各种传统应用的Exporter,完整的二次开发工具链,与Kubernetes等主流平台的高度亲和以及由此带来的强大的自发现 ...
- Scratch少儿编程系列:(十一)Scratch编程之简单见解
一.Scratch官网的说明 With Scratch, you can program your own interactive stories, games, and animations ...
- CF140C New Year Snowmen(贪心+优先队列)
CF140C 贪心+优先队列 贪心策略:每次取出数量最多的三种球,合成一个答案,再把雪球数都-1再插回去,只要还剩下三种雪球就可以不断地合成 雪球数用优先队列维护 #include <bits/ ...
- 启用yarn的高可用
选择高可用的主机,新的一台: 点运行结束后,会看到实例会多出一个备用的节点:
- Spring Cloud 使用Feign调用服务传递Header中的参数
1.使用Feign 调用其他微服务,尤其是在多级调用的同时,需要将一些共同的参数传递至下一个服务,如:token.比较方便的做法是放在请求头中,在Feign调用的同时自动将参数放到restTempla ...
- [官网]关于EPEL
EPEL/zh-cn https://fedoraproject.org/wiki/EPEL/zh-cn Contents [hide] 1企业版 Linux 附加软件包(EPEL) 1.1什么是企 ...
- 三校联训 【NOIP模拟】寻找
题面 “我有个愿望,我希望穿越一切找到你.” 这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三种(假设当前我在(x,y ...
- C++中的数据类模板
1,预备知识: 1,模板参数可以是数值型参数(非类型参数): 1,代码示例: template <typename T, int N> void func() { T a[N]; // 使 ...