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构图)的更多相关文章

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

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

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

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

  3. BZOJ5017 [Snoi2017]炸弹[线段树优化建边+scc缩点+DAG上DP/线性递推]

    方法一: 朴素思路:果断建图,每次二分出一个区间然后要向这个区间每个点连有向边,然后一个环的话是可以互相引爆的,缩点之后就是一个DAG,求每个点出发有多少可达点. 然后注意两个问题: 上述建边显然$n ...

  4. [SNOI2017]炸弹[线段树优化建图]

    [SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...

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

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

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

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

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

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

  8. bzoj千题计划196:bzoj4826: [Hnoi2017]影魔

    http://www.lydsy.com/JudgeOnline/problem.php?id=4826 吐槽一下bzoj这道题的排版是真丑... 我还是粘洛谷的题面吧... 提供p1的攻击力:i,j ...

  9. bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块

    http://www.lydsy.com/JudgeOnline/problem.php?id=4823 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...

随机推荐

  1. web前端监控的三个方面探讨

    一. js错误监控方式 1. 主动判断 我们在一些运算之后,得到一个期望的结果,然而结果不是我们想要的 // test.js function calc(){ // code... return va ...

  2. Android sqlitedatabase 事务

    SQLiteDatabase的beginTransaction()方法可以开启一个事务,程序执行到endTransaction() 方法时会检查事务的标志是否为成功,如果为成功则提交事务,否则回滚事务 ...

  3. luogu3674 小清新人渣的本愿 (bitset+莫队)

    对于加减,用bitset维护当前每个数有没有 对于乘,暴力枚举约数 然后莫队 复杂度$O(m(\sqrt{n}+\frac{c}{64}))$ #include<bits/stdc++.h> ...

  4. our happy ending(状压dp)

    题意:给定一个n,k,l. 问有多少长度为n的序列满足选出一些数使得他们相加为k,数列中每个数都在1-l以内. Solution 正解还是很妙的. 状压dp,设dp[i][j]表示长度为i的序列,能表 ...

  5. Duplicate entry 'xxx' for key 'xxx'

    插入数据的时候 报错,Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplic ...

  6. js 获取当前时间 年月日

    var datetime = new Date(); var year = datetime.getFullYear(); var month = datetime.getMonth() + 1 &l ...

  7. Opennebula常用命令

    查看虚拟机状态信息: [oneadmin@localhost /]$ onevm list 查看虚拟机配置: [oneadmin@localhost /]$ onevm show 25 启动虚拟机: ...

  8. JS小积累(一)— 判断在线离线

    JS小积累-判断在线离线 作者: 狐狸家的鱼 Github: 八至 if(window.navigator.onLine==true){ console.log('online'); ... } el ...

  9. Hadoop安装错误总结

    Master的NodeManager/DateNode未启动 日志中未出现任何错误 正常现象,如需在Master中启动可在slave文件中 slaves localhost slave01 slave ...

  10. BZOJ3512 DZY Loves Math IV

    解:这又是什么神仙毒瘤题...... 我直接把后面那个phi用phi * I = id反演一波,得到个式子,然后推不动了...... 实际上第一步我就大错特错了.考虑到n很小,我们有 然后计算S,我们 ...