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 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...
随机推荐
- 【HDU - 4342】History repeat itself(数学)
BUPT2017 wintertraining(15) #8C 题意 求第n(n<2^32)个非完全平方数m,以及\(\sum_{i=1}^m{\lfloor\sqrt i\rfloor}\) ...
- 【C++】实现一个简单的单例模式
- 洛谷P3602 Koishi Loves Segments(贪心,multiset)
洛谷题目传送门 贪心小水题. 把线段按左端点从小到大排序,限制点也是从小到大排序,然后一起扫一遍. 对于每一个限制点实时维护覆盖它的所有线段,如果超过限制,则贪心地把右端点最大的线段永远删去,不计入答 ...
- 【BZOJ1023】仙人掌图(仙人掌,动态规划)
[BZOJ1023]仙人掌图(仙人掌,动态规划) 题面 BZOJ 求仙人掌的直径(两点之间最短路径最大值) 题解 一开始看错题了,以为是求仙人掌中的最长路径... 后来发现看错题了一下就改过来了.. ...
- [2017-8-02]Android Learning Day9
Layout动画效果 为布局添加简单的动画效果 public class MainActivity extends AppCompatActivity { @Override protected vo ...
- 构建FTP服务
一.配置YUM仓库服务--------------YUM服务器------------------client------------------192.168.1.1 192.168.1.10[ro ...
- poj 2356 (抽屉原理)
题目链接:http://poj.org/problem?id=2356 题目大意:给你n个数,要你从n个数选出若干个数,要求这若干个数的和是n的倍数,输出选择数的个数,以及相应的数. 解题思路: 以下 ...
- 用lemon测交互题
题目类型:传统. 答案比较类型:逐行比较类型(忽略多余空格和制表符). 配置:交互. 编译器参数: -o %s %s.* ..\..\data\%s\judge.cpp -Wl,--stack= ju ...
- MD5加密解密类(asp.net)&使用MD5过时处理
加密类 #region ========加密======== /// <summary> /// 加密 /// </summary> /// <param name=&q ...
- python 装饰器的应用
import time def test1(): print "hello\n" print test1.__name__ def test2(): print "hel ...