SNOI2017炸弹
这个东西其实我是不太会的……但是勉强卡过去了。
首先肯定是建有向图,然后求每个节点能访问的节点个数,最裸的打法就是按照题意枚举建边然后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炸弹的更多相关文章
- [bzoj5017][Snoi2017]炸弹 tarjan缩点+线段树优化建图+拓扑
5017: [Snoi2017]炸弹 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 608 Solved: 190[Submit][Status][ ...
- [LOJ#2255][BZOJ5017][Snoi2017]炸弹
[LOJ#2255][BZOJ5017][Snoi2017]炸弹 试题描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: ...
- [SNOI2017]炸弹[线段树优化建图]
[SNOI2017]炸弹 线段树优化建图,然后跑一边tarjan把点全部缩起来,炸一次肯定是有连锁反应的所以整个连通块都一样-于是就可以发现有些是只有单向边的不能忘记更新,没了. #include & ...
- BZOJ5017题解SNOI2017炸弹--玄学递推
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5017 分析 老师讲课谈到了这道题,课上想出了个连边建图然后乱搞的操作,被老师钦定的递推方 ...
- [SNOI2017]炸弹
嘟嘟嘟 这题有一些别的瞎搞神奇做法,而且复杂度似乎更优,不过我为了练线段树,就乖乖的官方正解了. 做法就是线段树优化建图+强连通分量缩点+DAGdp. 如果一个炸弹\(i\)能引爆另一个炸弹\(j\) ...
- bzoj千题计划311:bzoj5017: [Snoi2017]炸弹(线段树优化tarjan构图)
https://www.lydsy.com/JudgeOnline/problem.php?id=5017 暴力: 对于每一个炸弹,枚举所有的炸弹,看它爆炸能不能引爆那个炸弹 如果能,由这个炸弹向引爆 ...
- BZOJ5017 [SNOI2017]炸弹 - 线段树优化建图+Tarjan
Solution 一个点向一个区间内的所有点连边, 可以用线段树优化建图来优化 : 前置技能传送门 然后就得到一个有向图, 一个联通块内的炸弹可以互相引爆, 所以进行缩点变成$DAG$ 然后拓扑排序. ...
- bzoj5017: [Snoi2017]炸弹
Description 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被 ...
- BZOJ5017 Snoi2017炸弹(线段树+强连通分量+缩点+传递闭包)
容易想到每个炸弹向其能引爆的炸弹连边,tarjan缩点后bitset传递闭包.进一步发现每个炸弹能直接引爆的炸弹是一段连续区间,于是线段树优化建图即可让边的数量降至O(nlogn).再冷静一下由于能间 ...
- 【bzoj5017】[Snoi2017]炸弹 线段树优化建图+Tarjan+拓扑排序
题目描述 在一条直线上有 N 个炸弹,每个炸弹的坐标是 Xi,爆炸半径是 Ri,当一个炸弹爆炸时,如果另一个炸弹所在位置 Xj 满足: Xi−Ri≤Xj≤Xi+Ri,那么,该炸弹也会被引爆. 现在 ...
随机推荐
- ubuntu14.04 x86编译upx 3.92 及so加固
的参考文章: http://www.cnblogs.com/fishou/p/4202061.html 1.download upx和所依赖的组件 upx3.:https://www.pysol.or ...
- 最全MySQL面试题和答案
Mysql 的存储引擎,myisam和innodb的区别. 答: 1.MyISAM 是非事务的存储引擎,适合用于频繁查询的应用.表锁,不会出现死锁,适合小数据,小并发. 2.innodb是支持事务的存 ...
- HBASE学习笔记(一)
一.数据库OLAP和OLTP简单的介绍比较 1.OLTP:on-line transaction processing在线事务处理,应用在传统关系型数据库比较多,执行日常基本的事务处理,比如数据库记录 ...
- C++typedef struct和struct的区别
#include "pch.h" #include struct struct1 { int a; char b; char* c; }test1;//定义结构体变量 typede ...
- Java学习笔记【七、时间、日期、数字】
参考:http://www.runoob.com/java/java-date-time.html Date类 构造: Date() 使用当前的日期时间 Date(long millisec) 197 ...
- Ceph自动化部署----Ceph-ansible
目录 Ceph自动化部署----Ceph-ansible 一.前言--Ceph的几种不同的部署方式 二.使用Ceph-ansible部署Ceph Ceph自动化部署----Ceph-ansible 一 ...
- 第四章·Kibana入门-安装,索引添加及界面功能
1.Kibana简介及部署 什么是Kibana? Kibana是一个通过调用elasticsearch服务器进行图形化展示搜索结果的开源项目. Kibana安装及配置 #将Kibana安装包上传至服务 ...
- 基于MYCAT中间件实现MYSQL读写分离
基于mycat实现mysql读写分离 完成主从复制的配置 /* 主节点:192.168.47.101 从节点:192.168.47.102 */ /*mycat为同一网段客户端*/ /* 修改主节点基 ...
- 【Swing】图形用户界面基础
前言 简单总结一下图形用户界面(Graphical User Interface)的相关基础,如GUI的基本元素:窗口,以及介绍Java中的图形界面开发设计的技术. 图形用户界面 图形用户界面就是以图 ...
- Java#Spring框架下注解解析
@Bean 定义Bean @Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里.添加的bean的id为方法名 @Configura ...