BZOJ5017 Snoi2017炸弹(线段树+强连通分量+缩点+传递闭包)
容易想到每个炸弹向其能引爆的炸弹连边,tarjan缩点后bitset传递闭包。进一步发现每个炸弹能直接引爆的炸弹是一段连续区间,于是线段树优化建图即可让边的数量降至O(nlogn)。再冷静一下由于能间接引爆的炸弹也是一段连续区间,传递闭包时只要记录可达点的左右端点即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 500010
#define M N<<2
#define ll long long
#define P 1000000007
ll read()
{
ll x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,p[M],dfn[M],low[M],stk[M],Set[M],L[M],R[M],root,t,cnt,top,tot,ans=;
bool flag[M];
ll a[N],b[N];
struct data{int to,nxt;
}edge[M<<];
struct data2{int l,r;
}tree[M];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void build(int &k,int l,int r)
{
if (l==r) {k=l;return;}
k=++cnt;
int mid=l+r>>;
build(tree[k].l,l,mid);
build(tree[k].r,mid+,r);
addedge(k,tree[k].l),addedge(k,tree[k].r);
}
void add(int k,int l,int r,int x,int y,int p)
{
if (l==x&&r==y) {addedge(p,k);return;}
int mid=l+r>>;
if (y<=mid) add(tree[k].l,l,mid,x,y,p);
else if (x>mid) add(tree[k].r,mid+,r,x,y,p);
else add(tree[k].l,l,mid,x,mid,p),add(tree[k].r,mid+,r,mid+,y,p);
}
void tarjan(int k)
{
dfn[k]=low[k]=++cnt;stk[++top]=k;flag[k]=;
for (int i=p[k];i;i=edge[i].nxt)
if (!dfn[edge[i].to]) tarjan(edge[i].to),low[k]=min(low[k],low[edge[i].to]);
else if (flag[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
if (dfn[k]==low[k])
{
tot++;L[tot]=n+,R[tot]=;
while (stk[top]!=k)
{
Set[stk[top]]=tot;
if (stk[top]<=n) L[tot]=min(L[tot],stk[top]),R[tot]=max(R[tot],stk[top]);
flag[stk[top]]=;
top--;
}
Set[k]=tot;if (k<=n) L[tot]=min(L[tot],k),R[tot]=max(R[tot],k);flag[k]=,top--;
}
}
namespace newgraph
{
int p[M]={},degree[M]={},q[M],t=;
struct data{int to,nxt;}edge[M<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;degree[y]++;}
void topsort()
{
int head=,tail=;
for (int i=;i<=tot;i++) if (!degree[i]) q[++tail]=i;
while (tail<tot)
{
int x=q[++head];
for (int i=p[x];i;i=edge[i].nxt)
{
degree[edge[i].to]--;
if (!degree[edge[i].to]) q[++tail]=edge[i].to;
}
}
}
void dp()
{
for (int i=tot;i>=;i--)
{
int x=q[i];
for (int j=p[x];j;j=edge[j].nxt)
L[x]=min(L[x],L[edge[j].to]),R[x]=max(R[x],R[edge[j].to]);
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj5017.in","r",stdin);
freopen("bzoj5017.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=;i<=n;i++) a[i]=read(),b[i]=read();
cnt=n;
build(root,,n);
for (int i=;i<=n;i++)
{
int x,y;
int l=,r=i;
while (l<=r)
{
int mid=l+r>>;
if (a[i]-b[i]<=a[mid]) x=mid,r=mid-;
else l=mid+;
}
l=i,r=n;
while (l<=r)
{
int mid=l+r>>;
if (a[i]+b[i]>=a[mid]) y=mid,l=mid+;
else r=mid-;
}
add(root,,n,x,y,i);
}
t=cnt;cnt=;
for (int i=;i<=t;i++) if (!dfn[i]) tarjan(i);
for (int k=;k<=t;k++)
for (int i=p[k];i;i=edge[i].nxt)
if (Set[k]!=Set[edge[i].to]) newgraph::addedge(Set[k],Set[edge[i].to]);
newgraph::topsort();
newgraph::dp();
for (int i=;i<=n;i++) ans=(ans+1ll*i*(R[Set[i]]-L[Set[i]]+))%P;
cout<<ans;
return ;
}
BZOJ5017 Snoi2017炸弹(线段树+强连通分量+缩点+传递闭包)的更多相关文章
- BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]
方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...
- bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- [SNOI2017]炸弹[线段树优化建图]
[SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点
loj#2255. 「SNOI2017」炸弹 线段树优化建图,拓扑,缩点 链接 loj 思路 用交错关系建出图来,发现可以直接缩点,拓扑统计. 完了吗,不,瓶颈在于边数太多了,线段树优化建图. 细节 ...
- bzoj5017: [Snoi2017]炸弹
Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被 ...
- HDU 3639 Hawk-and-Chicken(强连通分量+缩点)
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u013480600/article/details/32140501 HDU 3639 Hawk-a ...
- POJ1236Network of Schools[强连通分量|缩点]
Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 16571 Accepted: 65 ...
随机推荐
- RHCSA-考前准备
1.考前准备 RHCSA classroom虚拟机和server虚拟机 将两台虚拟机切换到初始化快照 打开虚拟机电源,当出现提示时选择我已移动该虚拟机 系统密码: classroom: root As ...
- day 7 引用
1.b=a在c语言和python中的区别 c语言:a=100 a变量里面放的100 b = a b变量里面也放的100 python : a=100 内存中有个100 a放的100 ...
- Oracle用户和模式,表空间
oracle 用户与表空间关系 oracle用户与表空间关系用户=商家表=商品表空间=仓库1. 1个商家能有很多商品,1个商品只能属于一个商家2. 1个商品可以放到仓库A,也可以放到仓库B,但不能同时 ...
- windows环境下apache-apollo服务器搭建及发布订阅测试
查证了一些资料之后,发现 apache-apollo服务器使用的人还是挺多的,资料也比较齐全,所以直接选择 apache-apollo了,具体性能如何,先用起来再说吧: 1.下载 apache-apo ...
- CSP201512-2:消除类游戏
引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...
- Zabbix_agnet部署
原文发表于cu:2016-05-18 参考文档: zabbix监控linux主机:http://www.osyunwei.com/archives/8035.html 一.环境 Server:基于C ...
- golang笔记2_程序结构
golang程序结构 2.1 命名 Golang中的命名遵循这样一个简单原则,名字的开头必须是字母或者下划线,后面跟字母.数字或者下划线(这里与C语言中是一致的). 在函数内部声明的实体,即局部变量, ...
- scrum立会报告+燃尽图(第二周第六次)
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2251 一.小组介绍 组名:杨老师粉丝群 组长:乔静玉 组员:吴奕瑶.公冶 ...
- 作业MathExamV2.0
MathExam233 211614269 林凯 211601233张康凌 一.预估与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时( ...
- 网页调用vlc并播放网络视频
环境:windows/android/ios windows端保存以下内容为reg文件并运行 Windows Registry Editor Version 5.00 [HKEY_CLASSES_RO ...