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,那么,该炸弹也会被引爆. 现在 ...
随机推荐
- JS基础_基本数据类型和引用数据类型
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- canva绘制圆角矩形
在做组态的时候,需要支持矩形圆角格式,但是因为canvas本身不带有圆角矩形,需要自行算出坐标进行绘制 方案一.统一圆角 <!DOCTYPE html> <html> < ...
- 这是一个用于判断IE浏览器版本的紧凑脚本
这是一个用于判断IE浏览器版本的紧凑脚本IE浏览器,不管它们是什么版本,总是与Web标准有些不兼容.对于编码人员来说,这很困难.为了考虑IE的兼容性,不管它是写CSS还是写JS,IE通常都会被特殊处理 ...
- 巧用Map缓存提升"翻译"速度
在业务编码中,很多情况都需要用到code2Name或者id2Name之间的"翻译",在我的过往经历中发现不少开发人员都是直接双重循环实现这种"翻译".如果一次& ...
- spring framework体系结构及模块jar依赖关系
本文对于Spring的JAR包使用和配置,结合网友材料以spring 4.3.6.RELEASE版本为例,介绍spring框架结构和各模块对应JAR包以及模块间JAR依赖关系. 注:不同版本JAR包依 ...
- jquery 取指定class下的input checkbox选中的值
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Windows环境中编译opencv3.0同时加入OPENCV_contrib库及解决遇到相关问题[contrib 必须要3.1以上的opencv才支持了]
更新:现在contrib库必须要opencv3.1以上才能支持编译通过了. 方法和步骤还是和本篇文章一样. ############################################## ...
- yocto 编译C程序
1. 找到编译器位置所在(相关设置参考/opt/poky/1.7/environment-setup-cortexa9hf-vfp-neon-poky-linux-gnueabi文件) poky安装在 ...
- Oracle【增删改&数据的备份】
增删改的SQL语句执行完毕后,不会立马进行数据的写入数据库(这时数据在内存中),需要手动对数据进行提交(commit),如果数据出问题,可以使用回滚.主键:非空唯一的 --在一张表中,某字段值是非空唯 ...
- Python:面向对象编程3 定制类(有更新)
Python:面向对象编程3 定制类(有更新) ⚠️本文主要内容为对Data model相关知识点的提取学习记录.(内容来自文档和部分网页教程案例) ⚠️:这个连接指向<流畅的python&g ...