bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)
https://www.lydsy.com/JudgeOnline/problem.php?id=5017
暴力:
对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹
如果能,由这个炸弹向引爆的炸弹连单向边
tarjan所点后拓扑排序
在拓扑图上倒着统计答案
可以得到一个炸弹能引爆的编号最小mi和最大的炸弹mx,mx-mi+1就是先引爆这个炸弹一共能引爆的炸弹数
优化:
一个炸弹一定是向一段区间连边
所以用线段树优化,这样向一个区间连边就变成了向一个点连边
注意存边的空间一定要开的足够大
还有tarjan缩完点后不一定是一棵树,因为是有向图缩点
#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm> using namespace std; const int mod=1e9+; #define N 500001 typedef long long LL; int n; int id[N*],num;
int front[N*],to[N*],nxt[N*],from[N*],tot; LL pos[N],rad[N]; int dfn[N*],low[N*],tim;
int st[N*],top;
bool vis[N*]; int cnt;
int bl[N*],mi[N*],mx[N*]; vector<int>V[N*];
int in[N*]; int q[N*]; template<typename T>
void read(T &x)
{
x=; int f=; char c=getchar();
while(!isdigit(c)) { if(c=='-') f=-; c=getchar(); }
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
x*=f;
} void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u;
//printf("%d %d\n",u,v);
} /*void add2(int u,int v)
{
to2[++tot2]=v; nxt2[tot2]=front2[u]; front2[u]=tot2;
}*/ void build(int k,int l,int r)
{
id[k]=++num;
if(l==r)
{
add(id[k],l);
return;
}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
add(id[k],id[k<<]);
add(id[k],id[k<<|]);
} void burst(int k,int l,int r,int opl,int opr,int who)
{
if(l>=opl && r<=opr)
{
add(who,id[k]);
return;
}
int mid=l+r>>;
if(opl<=mid) burst(k<<,l,mid,opl,opr,who);
if(opr>mid) burst(k<<|,mid+,r,opl,opr,who);
} void init()
{
read(n);
num=n;
build(,,n);
for(int i=;i<=n;++i) read(pos[i]),read(rad[i]);
for(int i=;i<=n;++i) burst(,,n,lower_bound(pos+,pos+n+,pos[i]-rad[i])-pos,upper_bound(pos+,pos+n+,pos[i]+rad[i])-pos-,i);
} void tarjan(int x)
{
dfn[x]=low[x]=++tim;
st[++top]=x;
vis[x]=true;
for(int i=front[x];i;i=nxt[i])
if(!dfn[to[i]])
{
tarjan(to[i]);
low[x]=min(low[x],low[to[i]]);
}
else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
int y;
if(low[x]==dfn[x])
{
cnt++;
mi[cnt]=n+;
mx[cnt]=;
while(x!=y)
{
y=st[top--];
vis[y]=false;
bl[y]=cnt;
if(y<=n)
{
mi[cnt]=min(mi[cnt],y);
mx[cnt]=max(mx[cnt],y);
}
}
}
} void rebuild()
{
for(int i=;i<=tot;++i)
if(bl[from[i]]!=bl[to[i]])
{
//add2(bl[from[i]],bl[to[i]]);
V[bl[from[i]]].push_back(bl[to[i]]);
in[bl[to[i]]]++;
}
} void topsort()
{
int head=,tail=;
for(int i=;i<=cnt;++i)
if(!in[i]) q[tail++]=i;
int now,siz,t;
while(head<tail)
{
now=q[head++];
siz=V[now].size();
for(int i=;i<siz;++i)
{
t=V[now][i];
in[t]--;
if(!in[t]) q[tail++]=t;
}
}
for(int i=tail-;i;--i)
{
now=q[i];
siz=V[now].size();
for(int i=;i<siz;++i)
{
t=V[now][i];
mi[now]=min(mi[now],mi[t]);
mx[now]=max(mx[now],mx[t]);
}
}
} void work()
{
// printf("%d %d\n",num,tot);
for(int i=;i<=num;++i)
if(!dfn[i]) tarjan(i);
rebuild();
topsort();
int ans=;
for(int i=;i<=n;++i)
{
ans+=1LL*i*(mx[bl[i]]-mi[bl[i]]+)%mod;
ans-=ans>=mod ? mod : ;
}
printf("%d",ans);
} int main()
{
init();
work();
}
bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)的更多相关文章
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能 ...
- BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]
方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...
- [SNOI2017]炸弹[线段树优化建图]
[SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...
- 【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缩点+建反边+跑拓扑
这道题我做了有半个月了...终于A了... 有图为证 一句话题解:二分LR线段树优化建边+tarjan缩点+建反边+跑拓扑统计答案 首先我们根据题意,判断出来要炸弹可以连着炸,就是这个炸弹能炸到的可以 ...
- bzoj千题计划196:bzoj4826: [Hnoi2017]影魔
http://www.lydsy.com/JudgeOnline/problem.php?id=4826 吐槽一下bzoj这道题的排版是真丑... 我还是粘洛谷的题面吧... 提供p1的攻击力:i,j ...
- bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块
http://www.lydsy.com/JudgeOnline/problem.php?id=4823 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...
随机推荐
- BZOJ 3514: Codechef MARCH14 GERALD07加强版(LCT + 主席树)
题意 \(N\) 个点 \(M\) 条边的无向图,询问保留图中编号在 \([l,r]\) 的边的时候图中的联通块个数. \(K\) 次询问强制在线. \(1\le N,M,K \le 200,000\ ...
- 自学Python之路-django
自学Python之路-django 自学Python之路[第一回]:1.11.2 1.3
- Android RadioGroup中设置默认选中RadioButton 后,选中两个的问题 解决方法
项目中遇到多个RadioGroup中单选RadioButton ,设置了默认选中第一个 . 然后就 能选中两个RadioButton . . .. 我开始这样给设置默认选中一个的: for (int ...
- 【Luogu4781】【模板】拉格朗日插值
[Luogu4781][模板]拉格朗日插值 题面 洛谷 题解 套个公式就好 #include<cstdio> #define ll long long #define MOD 998244 ...
- Codeforces | CF1000B 【Light It Up】
蒟蒻第二篇题解... 比赛的时候写这道题MLE了qwq..根据CF的赛制我也没敢再交第二次.. 简单讲一下思路好了(假装是dalao)..根据题意要加一个或者不加新的点..如果加一个新的点意味着从这个 ...
- HR_Sherlock and Anagrams_TIMEOUT[UNDONE]
2019年1月10日15:39:23 去掉了所有不必要的循环区间 还是超时 本地运行大概3s #!/bin/python3 import math import os import random im ...
- thinkphp5中__PUBLIC__的使用
在使用thinkphp5.1开发的时候遇到设置__PUBLIC__无法生效的问题.这次的版本升级有比较大的改动,很多写法已经被更改,下面说下怎么去解决这个问题. 工具/原料 phpstorm ln ...
- Lambda 表达式有何用处?如何使用?
强烈推荐!!! 作者:Sevenvidia链接:https://www.zhihu.com/question/20125256/answer/324121308来源:知乎著作权归作者所有.商业转载 ...
- 洛谷P3321 序列统计
气死了,FFT了半天发现是NTT... 1004535809 这个东西是NTT模数,原根为3. 题意:给定集合,元素的大小不超过M.用这些元素组成长为n的序列,要求乘积模M为k,求方案数. n < ...
- 洛谷P3723 礼物
以前看到过,但是搞不倒.知道了算法之后就好搞了. 题意:给定两个长为n的序列,你可以把某个序列全部加上某个数c,变成循环同构序列. 求你操作后的min∑(ai - bi)² 解: 设加上的数为c,那么 ...