题目链接

LOJ 2529

BZOJ 5308

题解

这么简单的题

为什么考场上我完全想不清楚 = =

对于k个关键点中的每一个关键点\(a\),二分它能一度成为哪些点的最短路起点(显然这些点在一段包含\(a\)的连续区间中),所以二分这个区间的左右端点。

如何判断某个点\(p\)是否在这个区间内呢?设\(d = |a - p|\),则\(a\)可以更新\(p\)当且仅当区间\([p - d, p + d]\)中的关键点到\(p\)的距离没有比\(a\)更优的。

设\(sum_i\)点\(i\)到点\(1\)的距离,用ST表维护一个关键点区间中\((sum_i - l)_{\max}\)和\((sum_i + l)_{\min}\),则\([p - d, p + d]\)中对于\(p\)的最优关键点可能是\([p - d, p]\)中\(sum_i - l\)最大的或\((p, p+d]\)中\(sum_i + l\)最小的。将他俩与\(a\)比较,如果\(a\)仍然是最优的,则\(a\)可以一度占领\(p\)这个点。

注意若两个关键点到\(p\)的距离相同,只能算一个,那么人为规定一下【离\(p\)边数最小的】是最优的,如果两个点这一项也一样,则取编号较小的即可。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define enter putchar('\n')
#define space putchar(' ')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op == 1) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
} const int N = 200005;
const ll INF = 1e18 + 233;
int n, m, K, lg[N];
ll sum[N], st1[N][20], st2[N][20], l1[N], l2[N];
struct Edge {
int a;
ll l;
Edge(){}
Edge(int x, ll y): a(x), l(y){}
bool operator < (const Edge &b) const {
return a < b.a;
}
} e[N]; int Max(int a, int b){
if(l1[a] == l1[b]) return max(a, b);
return l1[a] > l1[b] ? a : b;
}
int Min(int a, int b){
if(l2[a] == l2[b]) return min(a, b);
return l2[a] < l2[b] ? a : b;
}
void init(){
sort(e + 1, e + K + 1);
for(int i = 1; i <= K; i++){
l1[i] = sum[e[i].a] - e[i].l, l2[i] = sum[e[i].a] + e[i].l;
st1[i][0] = st2[i][0] = i;
}
for(int j = 1; (1 << j) <= K; j++)
for(int i = 1; i + (1 << j) - 1 <= K; i++){
st1[i][j] = Max(st1[i][j - 1], st1[i + (1 << (j - 1))][j - 1]);
st2[i][j] = Min(st2[i][j - 1], st2[i + (1 << (j - 1))][j - 1]);
}
}
int get1(int l, int r){
int j = lg[r - l + 1];
return Max(st1[l][j], st1[r - (1 << j) + 1][j]);
}
int get2(int l, int r){
int j = lg[r - l + 1];
return Min(st2[l][j], st2[r - (1 << j) + 1][j]);
}
int better(int a, int b, int p){
ll ans1 = e[a].l + abs(sum[p] - sum[e[a].a]);
ll ans2 = e[b].l + abs(sum[p] - sum[e[b].a]);
if(ans1 != ans2) return ans1 < ans2 ? a : b;
if(abs(e[a].a - p) != abs(e[b].a - p))
return abs(e[a].a - p) < abs(e[b].a - p) ? a : b;
return min(a, b);
}
bool bel(int p, int k){
int d = abs(e[k].a - p), best = k;
int l = lower_bound(e + 1, e + K + 1, Edge(p - d, 0)) - e;
int r = upper_bound(e + 1, e + K + 1, Edge(p + d, 0)) - e - 1;
int mid = upper_bound(e + 1, e + K + 1, Edge(p, 0)) - e - 1;
if(l <= mid) best = better(best, get1(l, mid), p);
if(mid < r) best = better(best, get2(mid + 1, r), p);
return best == k;
}
ll solve(){
ll ans = 0;
for(int i = 1; i <= K; i++){
int l = 1, r = e[i].a, mid, L;
while(l < r)
if(bel(mid = (l + r) >> 1, i)) r = mid;
else l = mid + 1;
L = l, l = e[i].a, r = n;
while(l < r)
if(bel(mid = (l + r + 1) >> 1, i)) l = mid;
else r = mid - 1;
ans += (r - L + 1);
}
return ans;
} int main(){ for(int i = 2; i < N; i++)
lg[i] = lg[i >> 1] + 1;
read(n), read(m);
for(int i = 2; i <= n; i++)
read(sum[i]), sum[i] += sum[i - 1];
while(m--){
read(K);
for(int i = 1; i <= K; i++)
read(e[i].a), read(e[i].l);
init();
write(solve()), enter;
} return 0;
}

BZOJ 5308 [ZJOI2018] Day2T2 胖 | 二分 ST表的更多相关文章

  1. 「ZJOI2018」胖(ST表+二分)

    「ZJOI2018」胖(ST表+二分) 不开 \(O_2\) 又没卡过去是种怎么体验... 这可能是 \(ZJOI2018\) 最简单的一题了...我都能 \(A\)... 首先我们发现这个奇怪的图每 ...

  2. ZJOI2018 胖 二分 ST表

    原文链接https://www.cnblogs.com/zhouzhendong/p/ZJOI2018Day2T2.html 题目传送门 - BZOJ5308 题目传送门 - LOJ2529 题目传送 ...

  3. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

  4. BZOJ3166 [Heoi2013]Alo 【可持久化trie树 + 二分 + ST表】

    题目 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG , 如名字所见,到处充满了数学的谜题. 现在你拥有n颗宝石,每颗宝石 ...

  5. [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表

    [BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 ...

  6. 洛谷P4501/loj#2529 [ZJOI2018]胖(ST表+二分)

    题面 传送门(loj) 传送门(洛谷) 题解 我们对于每一个与宫殿相连的点,分别计算它会作为多少个点的最短路的起点 若该点为\(u\),对于某个点\(p\)来说,如果\(d=|p-u|\),且在\([ ...

  7. BZOJ 3230 相似子串 | 后缀数组 二分 ST表

    BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...

  8. bzoj 3230: 相似子串【SA+st表+二分】

    总是犯低级错误,st表都能写错-- 正反分别做一遍SA,预处理st表方便查询lcp,然后处理a[i]表示前i个后缀一共有多少个本质不同的子串,这里的子串是按字典序的,所以询问的时候直接在a上二分排名就 ...

  9. HDU5726 GCD(二分 + ST表)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5726 Description Give you a sequence of N(N≤100, ...

随机推荐

  1. Luogu P3374 【模板】树状数组 1

    真正的模板题. 树状数组的思想很简单(不如说背代码更简单),每个节点记录多个节点的信息(每个点存x&(-x)个). 道理可以参见很多大佬的博客,最后前缀和的思想搞一下就好了.不想说也不会说. ...

  2. dp方法论——由矩阵相乘问题学习dp解题思路

    前篇戳:dp入门——由分杆问题认识动态规划 导语 刷过一些算法题,就会十分珍惜“方法论”这种东西.Leetcode上只有题目.讨论和答案,没有方法论.往往答案看起来十分切中要害,但是从看题目到得到思路 ...

  3. FFMPEG指令

    FFmpeg是一个用于音视频处理的自由软件,被广泛用于音视频开发.FFmpeg功能强大,本文主要介绍如何使用FFmpeg命令行工具进行简单的视频处理. 安装FFmpeg可以在官网下载各平台软件包或者静 ...

  4. python基础学习笔记(五)

    字符串基本操作 所有标准的序列操作(索引.分片.乘法.判断成员资格.求长度.取最小值和最大值)对字符串同样适用,前面已经讲述的这些操作.但是,请注意字符串都是不可变的. 字符串的方法: 字符串从str ...

  5. 12.24daily_scrum

    今天是平安夜,大家开心地度过一个平安夜的同时,也完成了很多软件的调试工作,我们争取在下周前完成本阶段的所有调试工作. 具体工作如下: 具体工作: 小组成员 今日任务 明日任务 工作时间 李睿琦 软件调 ...

  6. Can't find model 'en'

    在使用 nlp = spacy.load("en") 报错OSError: Can't find model 'en' 应该用 python -m spacy download e ...

  7. Github介绍

    Git是一个分布式的版本控制系统,最初由LinusTorvalds编写,用作Linux内核代码的管理.在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中.包括Rubinius和Mer ...

  8. 第三个spring冲刺总结(附团队贡献分)

    基于调查需求下完成的四则运算,我们完成了主要的3大功能. 第一,普通的填空题运算,这个是传统的运算练习方式,团队都认为这个选项是必要的,好的传统要留下来,在个人经历中,填空练习是一个不错的选择. 第二 ...

  9. Java实现小学四则运算练习系统(UI)

    github项目地址 :https://github.com/feser-xuan/Arithmetic_test3_UI 小伙伴的博客链接:http://www.cnblogs.com/fukang ...

  10. Golang的格式化输出fmt.Printf

    本文来源:Go by example. Golang的格式化输出 和 C语言的标准输出基本一样,但是增加了一些针对Golang语言的特有数据结构的格式化输出方式. 一下就是实例: package ma ...