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

首先肯定是建有向图,然后求每个节点能访问的节点个数,最裸的打法就是按照题意枚举建边然后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. Linux Too many open files

    Linux Too many open files 查看系统资源限制信息: sudo -s -u root -H id sudo -s lsof | awk '{ print $2 " &q ...

  2. C# 知识点笔记:IEnumerable<>的使用,利用反射动态调用方法

    IEnumerable<T>的使用 创建一个IEnumerable对象 List<string> fruits = new List<string> { " ...

  3. 短信对接——一种jdbc链接运用

    package sms; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamRead ...

  4. centos 7 firewall(防火墙)开放端口/删除端口/查看端口

    1.firewall的基本启动/停止/重启命令 复制#centos7启动防火墙 systemctl start firewalld.service #centos7停止防火墙/关闭防火墙 system ...

  5. linux基础—课堂随笔05_文本三剑客之SED

    1.简介 sed是非交互式的编辑器,它不会修改文件,除非使用shell重定向来保存结果.默认情况下,所有的输出行都被打印到屏幕上. sed编辑器逐行处理文件(或输入),并将结果发送到屏幕.具体过程如下 ...

  6. 自动化测试 selenium 测试软件安装

      一.自动化测试优点 1.对程序的回归测试更方便.在程修改的比较平凡的时候,表现的更明显. 2.可以代替测试人员运行更繁琐的测试,也可以代替测试人员不可能完成的操作(比如连续点击50次) 3.更好的 ...

  7. 【获取url 问号后参数】防中文乱码

    function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&] ...

  8. Type反射遍历类的属性

    <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup& ...

  9. Vue快速学习_第五节

    axios安装及使用 网站文档地址:https://www.kancloud.cn/yunye/axios/234845 1.npm安装 cnpm install axios 2.// 在main.j ...

  10. zencart产品批量表上传后SEO三要素状态以及特价时间修改

    ', metatags_products_name_status ', metatags_model_status ', metatags_price_status ', metatags_title ...