这个东西其实我是不太会的……但是勉强卡过去了。

首先肯定是建有向图,然后求每个节点能访问的节点个数,最裸的打法就是按照题意枚举建边然后tarjan缩点,用bitset记录一下访问节点,但是bitset开不了那么大,只能拿到50%的分,至于开数组枚举我没有试,目测高不了多少。

然后思考这样一个问题,我建的那么多边真的有用么。于是只建离他最近的两个点的边,然后直接topsort统计ans,能拿到80%的数据。

然后就不会了……

去loj看一眼,有一组小的hack数据,异常难受。

看看别人的打法,不是直接统计ans,而是记录这个点所能到达的最左点l[x]和最右点r[x],然后r[x]-l[x]+1就是他能引爆的炸弹数。可以AC。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <bitset>
#include <map>
#define ll long long
using namespace std;
struct EDGE {
int ed, nex;
} edge[], edgec[];
int first[], firstc[], numc, num;
struct Point {
ll x, r;
} p[];
ll read() {
ll sum = ;
int f = ;
char x = getchar();
while (x < '' || x > '') {
if (x == '-')
f = -;
x = getchar();
}
while (x >= '' && x <= '') {
sum = sum * + x - '';
x = getchar();
}
return sum * f;
}
ll n, ans1;
const int mod = 1e9 + ;
const int inf=0x7fffffff;
int dfn[], low[], sta[], bl[], du[];
int ord, sccnum, top,l[],r[];
vector<int> scc[];
bool ins[];
void add(int st, int ed) {
// cout<<"st="<<st<<" ed="<<ed<<endl;
edge[++num].ed = ed;
edge[num].nex = first[st];
first[st] = num;
}
void addc(int st, int ed) {
// cout<<"stc="<<st<<" edc="<<ed<<endl;
edgec[++numc].ed = ed;
edgec[numc].nex = firstc[st];
firstc[st] = numc;
}
void topsort() {
queue<int> q;
for (int i = ; i <= sccnum; i++)
if (!du[i])
q.push(i);
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = firstc[x]; i; i = edgec[i].nex) {
int y = edgec[i].ed;
du[y]--;
l[y]=min(l[y],l[x]);
r[y]=max(r[y],r[x]);
if (!du[y])
q.push(y);
}
}
}
void tarjan(int x) {
dfn[x] = low[x] = ++ord;
sta[++top] = x;
ins[x] = ;
for (int i = first[x]; i; i = edge[i].nex) {
int y = edge[i].ed;
if (!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
} else if (ins[y])
low[x] = min(low[x], dfn[y]);
}
if (dfn[x] == low[x]) {
sccnum++;
int p;
do {
p = sta[top--];
ins[p] = ;
l[sccnum]=min(l[sccnum],p);
r[sccnum]=max(r[sccnum],p);
bl[p] = sccnum;
scc[sccnum].push_back(p);
} while (x != p);
}
}
int main() {
n = read();
for (int i = ; i <= n; i++) {
p[i].x = read();
p[i].r = read();
}
for(int i=;i<=n;i++){
l[i]=inf;
r[i]=-inf;
}
for (int i = ; i <= n; i++){
for (int j = i + ; j <= n; j++) {
if (j == i)
continue;
if (p[j].x - p[j].r <= p[i].x ) {
add(j, i);
break;
}
}
}
for (int i = n; i >= ; i--){
for (int j = i - ; j >= ; j--) {
if (j == i)
continue;
if ( p[i].x <= p[j].x + p[j].r) {
add(j, i);
break;
}
}
}
/* for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(i==j) continue;
if(p[i].x-p[i].r<=p[j].x&&p[j].x<=p[i].x+p[i].r)
add(i,j);
}*/
for (int i = ; i <= n; i++)
if (!dfn[i])
tarjan(i);
for (int i = ; i <= n; i++) {
for (int j = first[i]; j; j = edge[j].nex) {
int y = edge[j].ed;
if (bl[i] == bl[y])
continue;
addc(bl[y], bl[i]);
du[bl[i]]++;
}
}
/* for(int i=1;i<=sccnum;i++){
for(int j=0;j<scc[i].size();j++)
cout<<scc[i][j]<<" ";
cout<<endl;
}*/
topsort();
/* for(int i=1;i<=sccnum;i++)
cout<<ans[i]<<" ";cout<<endl;*/
for (int i = ; i <= n; i++)
ans1 = (ans1 + 1ll * i * (r[bl[i]]-l[bl[i]]+)) % mod;
printf("%lld", ans1);
return ;
}

有点错位,凑合看吧,应该好打。

SNOI2017炸弹的更多相关文章

  1. [bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑

    5017: [Snoi2017]炸弹 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 608  Solved: 190[Submit][Status][ ...

  2. [LOJ#2255][BZOJ5017][Snoi2017]炸弹

    [LOJ#2255][BZOJ5017][Snoi2017]炸弹 试题描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: ...

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

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

  4. BZOJ5017题解SNOI2017炸弹--玄学递推

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5017 分析 老师讲课谈到了这道题,课上想出了个连边建图然后乱搞的操作,被老师钦定的递推方 ...

  5. [SNOI2017]炸弹

    嘟嘟嘟 这题有一些别的瞎搞神奇做法,而且复杂度似乎更优,不过我为了练线段树,就乖乖的官方正解了. 做法就是线段树优化建图+强连通分量缩点+DAGdp. 如果一个炸弹\(i\)能引爆另一个炸弹\(j\) ...

  6. bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)

    https://www.lydsy.com/JudgeOnline/problem.php?id=5017 暴力: 对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹 如果能,由这个炸弹向引爆 ...

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

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

  8. bzoj5017: [Snoi2017]炸弹

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

  9. BZOJ5017 Snoi2017炸弹(线段树+强连通分量+缩点+传递闭包)

    容易想到每个炸弹向其能引爆的炸弹连边,tarjan缩点后bitset传递闭包.进一步发现每个炸弹能直接引爆的炸弹是一段连续区间,于是线段树优化建图即可让边的数量降至O(nlogn).再冷静一下由于能间 ...

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

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

随机推荐

  1. C#异步编程学习笔记之-async和await(续)

    书接上文,本篇主要记录的内容要点:1.针对async和await在实际应用中的使用方式:2.异步方法返回值(有返回值和无返回值)的两种情况: 示例一(无返回值): using System; usin ...

  2. git的详细安装

    git的详细安装 Git 是时候动手尝试下 Git 了,不过得先安装好它.有许多种安装方式,主要分为两种,一种是通过编译源代码来安装:另一种是使用为特定平台预编译好的安装包. 从源代码安装 若是条件允 ...

  3. 题解 P2859 【[USACO06FEB]摊位预订Stall Reservations】

    题目链接: https://www.luogu.org/problemnew/show/P2859 思路: 首先大家会想到这是典型的贪心,类似区间覆盖问题的思路,我们要将每段时间的左端点从小到大排序, ...

  4. centos 配置rsync+inotify数据实时同步

    何为rsync? 定义: rsync是一个开源的快速备份工具,可以在不同主机之间镜像同步整个目录树,支持增量备份,保持链接和权限,非常适用于异地备份 何为源端和发起端? 在远程同步过程中,负责发起rs ...

  5. css强制换行显示省略号之显示两行后显示省略号

    1,首先来一个固定宽度,在一行显示,超出隐藏,显示省略号的样式 display:block; white-space:nowrap; overflow:hidden; text-overflow:el ...

  6. Fiddler抓取手机APP程序数据包

    1.下载并安装Fiddler 下载地址:https://www.telerik.com/download/fiddler 2.设置Fiddler可监听远程通讯 前提条件:需要监听的手机和Fiddler ...

  7. 【4】Zookeeper数据模型

    一.Znode节点是什么 1.1.概念   Znode节点是Zookeeper中数据模型中最小的数据单元.Zookeeper的数据模型是一颗树,由"/"进行分割路径.每个znode ...

  8. 【转】container_of宏 分析

    在学习Linux驱动的过程中,遇到一个宏叫做container_of.该宏定义在include/linux/kernel.h中,首先来贴出它的代码: /** * container_of - cast ...

  9. 并发编程:协程TCP、非阻塞IO、多路复用、

    一.线程池实现阻塞IO 二.非阻塞IO模型 三.多路复用,降低CPU占用 四.模拟异步IO 一.线程池实现阻塞IO 线程阻塞IO 客户端 import socket c = socket.socket ...

  10. java8 stream().map().collect()用法

    有一个集合: List<User> users = getList(); //从数据库查询的用户集合 现在想获取User的身份证号码:在后续的逻辑处理中要用: 常用的方法我们大家都知道,用 ...