题面

传送门

分析

主体思路:若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)的更多相关文章

  1. 【2019.7.26 NOIP模拟赛 T3】化学反应(reaction)(线段树优化建图+Tarjan缩点+拓扑排序)

    题意转化 考虑我们对于每一对激活关系建一条有向边,则对于每一个点,其答案就是其所能到达的点数. 于是,这个问题就被我们搬到了图上,成了一个图论题. 优化建图 考虑我们每次需要将一个区间向一个区间连边. ...

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

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

  3. bzoj5017 炸弹 (线段树优化建图+tarjan+拓扑序dp)

    直接建图边数太多,用线段树优化一下 然后缩点,记下来每个点里有多少个炸弹 然后按拓扑序反向dp一下就行了 #include<bits/stdc++.h> #define pa pair&l ...

  4. 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序

    题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆.  现在 ...

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

    这道题我做了有半个月了...终于A了... 有图为证 一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案 首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以 ...

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

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

  7. 『炸弹 线段树优化建图 Tarjan』

    炸弹(SNOI2017) Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸 时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi ...

  8. 【2019北京集训2】duck 线段树优化建图+tarjan

    题目大意:给你$n$个点,第$i$个点有点权$v_i$.你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和 ...

  9. BZOJ5017 炸弹(线段树优化建图+Tarjan+拓扑)

    Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足:  Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被 ...

随机推荐

  1. pg_ctl - 启动,停止和重启 PostgreSQL 服务器

    SYNOPSIS pg_ctl start [ -w ] [ -s ] [ -D datadir] [ -l filename] [ -o options] [ -p path] pg_ctl sto ...

  2. centos误删除文件如何恢复

    当意识到误删除文件后,切忌千万不要再频繁写入了,否则你的数据恢复的数量将会很少. 而我们要做的是,第一时间把服务器上的服务全部停掉,直接killall 进程名 或者 kill -9 pid . 然后把 ...

  3. Jupyter配置工作路径

    在修改之前,C:\Users\Administrator\ .jupyter 目录下面只有一个“migrated”文件. 打开命令窗口(运行->cmd),进入python的Script目录下输入 ...

  4. linux--基础知识2

    #超级用户root的家目录是/root ,而普通用户的家目录被存放在/home目录下 cd /目录  切换到指定目录 注意 /  是根目录 linux的一些重要目录 1.bin目录,用来存放常用的可执 ...

  5. stream benchmark 介绍

    英文原版 https://www.cs.virginia.edu/stream/ref.html FAQ中有关于STREAM_ARRAY_SIZE NTIME OFFSET STREAM_TYPE的设 ...

  6. 前端每日实战:43# 视频演示如何用纯 CSS 绘制一个充满动感的 Vue logo

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/zaqKPx 可交互视频教程 此视频 ...

  7. web--响应式导航菜单

    响应式导航菜单 代码如下 HTML代码: <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  8. c#image与byte数组的转换

    // image to byte[] Image photo = new Bitmap(selectPictureFile); System.IO.MemoryStream ms = new Syst ...

  9. C#中给RICHTEXTBOX加上背景图片

    在系统自带的RichTextBox中是无法给它设置背景图片,但是我们在某些场合可能需要给RichTextBox设置背景图片.那么怎么实现这一想法呢?经过研究发现通过其它巧妙的途径可以给RichText ...

  10. MySQL JOIN 多表连接

    除了常用的两个表连接之外,SQL(MySQL) JOIN 语法还支持多表连接.多表连接基本语法如下: 1 ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON ...