Libre OJ 2255 (线段树优化建图+Tarjan缩点+DP)
题面
分析
主体思路:若x能引爆y,从x向y连一条有向边,最后的答案就是从x出发能够到达的点的个数
首先我们发现一个炸弹可以波及到的范围一定是坐标轴上的一段连续区间
我们可以用二分查找求出炸弹能波及到最左边和最右边的点,记为[l,r]
然后我们就需要向编号属于区间[l,r]的点连一条有向边
如果直接连边,时间复杂度为\(O(n^2)\) 无法接受,考虑用线段树优化连边
我们将线段树看成一个有向图,每个线段树节点看成图上的一个点,[l,r]向[l,mid],[mid+1,r]连边,叶子节点[l,l]向原图上的节点l连边
对于从x向编号属于区间[L,R]的点连边,我们用类似线段树区间更新的方法,将[L,R]拆成许多个小区间,再直接向这些小区间暴力连边

根据线段树的性质,最多会分出\(\left[ \log _{2}n\right]\)个节点,所以单次连边的时间复杂度为\(O(\log n)\)
然后就很套路了,显然环上的点可以缩成一个大点(权值为环上所有节点权值之和(线段树节点权值为0,原图上节点权值为1))
Tarjan完在DAG上DP即可
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define maxn 1700005
#define mod 1000000007
using namespace std;
inline void qread(int &x) {
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qread(long long &x) {
x=0;
long long sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
int n;
long long x[maxn];
long long r[maxn];
struct edge {
int from;
int to;
edge() {
}
edge(int u,int v) {
from=u;
to=v;
}
friend bool operator == (edge a,edge b) {
return a.to==b.to&&a.from==b.from;
}
friend bool operator < (edge a,edge b) {
if(a.from==b.from) return a.to<b.to;
else return a.from<b.from;
}
};
set<edge>vis1;
set<edge>vis2;
vector<int>G[maxn],D[maxn];
int w[maxn];
void add_edge(int u,int v) {
G[u].push_back(v);
}
int newn=n;
struct node {
int l;
int r;
} tree[maxn];
void build(int l,int r,int pos) {
newn++;
tree[pos].l=l;
tree[pos].r=r;
if(l==r) {
add_edge(pos+n,l);
return;
}
add_edge(pos+n,pos*2+n);
add_edge(pos+n,pos*2+1+n);
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
}
void update(int L,int R,int v,int pos) {
if(L<=tree[pos].l&&R>=tree[pos].r) {
add_edge(v,pos+n);
return;
}
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,v,pos<<1);
if(R>mid) update(L,R,v,pos<<1|1);
}
stack<int>s;
int tim=0;
int m=0;
int ins[maxn];
int dfn[maxn];
int low[maxn];
int belong[maxn];
int sz[maxn];
void tarjan(int x) {
s.push(x);
ins[x]=1;
dfn[x]=low[x]=++tim;
int tmp=G[x].size();
for(int i=0; i<tmp; i++) {
int y=G[x][i];
if(!dfn[y]) {
tarjan(y);
low[x]=min(low[x],low[y]);
} else if(ins[y]) {
low[x]=min(low[x],dfn[y]);
}
}
if(low[x]==dfn[x]) {
m++;
int y;
do {
y=s.top();
s.pop();
ins[y]=0;
belong[y]=m;
sz[m]+=w[y];
} while(x!=y);
}
}
void dcg_to_dag() {
for(int i=1; i<=n; i++) {
if(!dfn[i]) tarjan(i);
}
int s;
for(int i=1; i<=n; i++) {
s=G[i].size();
for(int j=0; j<s; j++) {
if(belong[i]!=belong[G[i][j]]&&!vis2.count(edge(belong[i],belong[G[i][j]]))) {
vis2.insert(edge(belong[i],belong[G[i][j]]));
D[belong[i]].push_back(belong[G[i][j]]);
}
}
}
}
long long dp[maxn];
int dfs(int x){
if(dp[x]) return dp[x];
dp[x]=sz[x];
int tmp=D[x].size();
for(int i=0;i<tmp;i++){
int y=D[x][i];
dp[x]+=dfs(y);
}
return dp[x];
}
long long solve() {
long long ans=0;
for(int i=1;i<=n;i++){
if(!dp[i]) dfs(i);
}
for(int i=1; i<=n; i++) {
ans=(ans+w[i]*i*dp[belong[i]]%mod)%mod;
}
return ans;
}
int main() {
int L,R;
qread(n);
for(int i=1; i<=n; i++) {
w[i]=1;
qread(x[i]);
qread(r[i]);
}
newn=n;
build(1,n,1);
for(int i=1; i<=n; i++) {
L=lower_bound(x+1,x+1+n,x[i]-r[i])-x;
R=upper_bound(x+1,x+1+n,x[i]+r[i])-x-1;
update(L,R,i,1);
}
n=newn;
dcg_to_dag();
printf("%lld\n",solve());
}
Libre OJ 2255 (线段树优化建图+Tarjan缩点+DP)的更多相关文章
- 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)
题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...
- bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...
- bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)
直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
- 炸弹:线段树优化建边+tarjan缩点+建反边+跑拓扑
这道题我做了有半个月了...终于A了... 有图为证 一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案 首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以 ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- 『炸弹 线段树优化建图 Tarjan』
炸弹(SNOI2017) Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸 时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi ...
- 【2019北京集训2】duck 线段树优化建图+tarjan
题目大意:给你$n$个点,第$i$个点有点权$v_i$.你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和 ...
- BZOJ5017 炸弹(线段树优化建图+Tarjan+拓扑)
Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被 ...
随机推荐
- HBase HA分布式集群搭建
HBase HA分布式集群搭建部署———集群架构 搭建之前建议先学习好HBase基本构架原理:https://www.cnblogs.com/lyywj170403/p/9203012.html 集群 ...
- [转]Oracle 11g 基于CentOS7静默安装教程(无图形界面,远程安装) --有部份地方有问题
Oracle 11g 基于CentOS7静默安装教程(无图形界面,远程安装) [转载]原文地址:http://canonind.blog.51cto.com/8239025/1883066 一.安装前 ...
- tomcat启动报错:Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
windows系统: 部署了一个Tomcat8.5.15,bin目录下startup.bat执行,结果提示Neither the JAVA_HOME nor the JRE_HOME enviro ...
- Nginx安装与配置-Centos7
Nginx是一款高性能免费开源网页服务器,也可用于反向代理和负载均衡服务器.该软件由伊戈尔·赛索耶夫于2004年发布,2019年3月11日,Nginx被F5 Networks以6.7亿美元收购.201 ...
- Support for the experimental syntax 'decorators-legacy' isn't currently enabled (7:1):
1.产生原因:项目不支持装饰器 2.解决方法: 2.1 执行 yarn 安装完整依赖: 2.2 如果依赖时yarn.lock变化了,并且项目有git目录,则将提示的文件提交到git仓库 ? Are y ...
- 学习旧岛小程序 (1) flex 布局
css : view 相当于 div 块级元素 display 默认设置 block display:inline 设置后 设置宽度高度是无效的 要设置宽度高度 又要设置为行内元素 我们设置: (1) ...
- MySQL数据库的自动备份与数据库被破坏后的恢复1
一.前言: 当数据库服务器建立好以后,我们首先要做的不是考虑要在这个支持数据库的服务器运行哪些受MySQL提携的程序,而是当数据库遭到破坏后,怎样安然恢复到最后一次正常的状态,使得数据的损失达到最小. ...
- __getattr__属性查找
from datetime import date """ __getattr__ : 在查找不到对象的属性时调用 __getattribute__ : 在查找属性之前调 ...
- SSM项目web.xml等配置文件中如何查找类的全路径名?
如题, web.xml,applicationContext.xml 等配置文件中,有时不会出现自动提示类的名字,这时如何查找类的全路径名,如下图所示: 1.鼠标右键单击菜单栏Navigate选项,选 ...
- 2,ArrayList
一,ArrayList简介 1,ArrayList 是一个数组队列,相当于动态数组.与Java中的数组相比,它的容量能动态增长. 2,ArrayList 继承了AbstractList,实现了List ...