[ZJOI2018]胖
嘟嘟嘟
都说这题是送分题,但我怎么就不觉得的呢。
看来我还是太弱了啊……
大体思路就是对于每一个设计方案,答案就是每一个关键点能更新的点的数量之和。
关键在于怎么求一个关键点能更新那些点。
首先这些点肯定是一个包含关键点\(a_i\)的连续区间,于是可以二分找区间的左右端点。
具体是这样的:
对于一个点\(x\),判断这个点能否被\(a_i\)更新。
令\(d = |x - a_i|\),即\(x\)和\(a_i\)间边的数量。然后看从七点出发经过\([x - d, x + d]\)这个区间的所有关键点到\(x\)的距离有没有比\(a_i\)小的,如果没有,就说明\(x\)能被\(a_i\)更新。
这个倒也好理解,按照算法流程,对于每一个关键点,肯定是向两侧的点 一条边一条边更新的,而如果两个关键点同时更新到一个点的话,这个点一定取距离更小的点。
怎么高效的判断呢?也就是怎么快速的求出从起点出发经过一个区间内的所有关键点到指定点的距离的最小值。
首先预处理两点间距离前缀和。
如果\(a_i\)在\(x\)左面,那么这个距离等于\(l[a_i] + sum[x] - sum[a_i] = sum[x] + (l[a_i] - sum[a_i])\);如果在右面,距离就是\(l[a_i] + sum[a_i] - sum[x] = -sum[x] + (l[a_i] + sum[a_i])\)。
发现括号里的两个东西可以用st表维护(或线段树)。代码中是维护了\(l[a_i] + sum[a_i]\)的最小值和\(sum[a_i] - l[a_i]\)的最大值。
还有一个细节在于可能有两个关键点到\(x\)的距离相同,为了防止重复统计,强制规定编号小的点的距离更小。
复杂度\(O(nlog ^ 2n)\),loj上很愉快的过了,某谷上非得开O2。
别忘开long long。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e5 + 5;
const int N = 18;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m, K;
int lg[maxn];
ll sum[maxn];
struct Edge
{
int p; ll w;
In bool operator < (const Edge& oth)const
{
return p < oth.p;
}
}e[maxn];
ll dis1[maxn], dis2[maxn];
int Min[maxn][N + 2], Max[maxn][N + 2];
In int _min(int a,int b)
{
if(dis1[a] == dis1[b]) return min(a, b);
return dis1[a] < dis1[b] ? a : b;
}
In int _max(int a, int b)
{
if(dis2[a] == dis2[b]) return max(a, b);
return dis2[a] > dis2[b] ? a : b;
}
In void init()
{
sort(e + 1, e + K + 1);
for(int i = 1; i <= K; ++i)
{
dis1[i] = e[i].w + sum[e[i].p], dis2[i] = sum[e[i].p] - e[i].w;
Min[i][0] = Max[i][0] = i;
}
for(int j = 1; (1 << j) <= K; ++j)
for(int i = 1; i + (1 << j) - 1 <= K; ++i)
{
Min[i][j] = _min(Min[i][j - 1], Min[i + (1 << (j - 1))][j - 1]);
Max[i][j] = _max(Max[i][j - 1], Max[i + (1 << (j - 1))][j - 1]);
}
}
In int query_Min(int L, int R)
{
int k = lg[R - L + 1];
return _min(Min[L][k], Min[R - (1 << k) + 1][k]);
}
In int query_Max(int L, int R)
{
int k = lg[R - L + 1];
return _max(Max[L][k], Max[R - (1 << k) + 1][k]);
}
In int update(int a, int b, int x)
{
ll ans1 = e[a].w + abs(sum[x] - sum[e[a].p]);
ll ans2 = e[b].w + abs(sum[x] - sum[e[b].p]);
if(ans1 ^ ans2) return ans1 < ans2 ? a : b;
int nod1 = abs(e[a].p - x), nod2 = abs(e[b].p - x);
if(nod1 ^ nod2) return nod1 < nod2 ? a : b;
return min(a, b);
}
In bool judge(int x, int t)
{
int d = abs(x - e[t].p), ret = t;
int l = lower_bound(e + 1, e + K + 1, (Edge){x - d, 0}) - e;
int r = upper_bound(e + 1, e + K + 1, (Edge){x + d, 0}) - e - 1;
int mid = upper_bound(e + 1, e + K + 1, (Edge){x, 0}) - e - 1;
if(l <= mid) ret = update(ret, query_Max(l, mid), x);
if(mid < r) ret = update(ret, query_Min(mid + 1, r), x);
return ret == t;
}
In ll solve()
{
ll ret = 0;
for(int i = 1, ansL, ansR; i <= K; ++i)
{
int L = 1, R = e[i].p, mid;
while(L < R)
if(judge(mid = (L + R) >> 1, i)) R = mid;
else L = mid + 1;
ansL = L;
L = e[i].p, R = n;
while(L < R)
if(judge(mid = (L + R + 1) >> 1, i)) L = mid;
else R = mid - 1;
ansR = L;
ret += ansR - ansL + 1;
}
return ret;
}
int main()
{
#ifdef mrclr
freopen("t2.in", "r", stdin);
freopen("ha.out", "w", stdout);
#endif
n = read(), m = read();
for(int i = 2; i < maxn; ++i) lg[i] = lg[i >> 1] + 1;
for(int i = 2; i <= n; ++i) sum[i] = read(), sum[i] += sum[i - 1];
for(int i = 1; i <= m; ++i)
{
K = read();
for(int j = 1; j <= K; ++j) e[j].p = read(), e[j].w = read();
init();
write(solve()), enter;
}
return 0;
}
[ZJOI2018]胖的更多相关文章
- 【BZOJ5308】[ZJOI2018]胖(模拟,ST表,二分)
[BZOJ5308][ZJOI2018]胖(模拟,ST表,二分) 题面 BZOJ 洛谷 题解 首先发现每条\(0\)出发的边都一定会更新到底下的一段区间的点. 考虑存在一条\(0\rightarrow ...
- 5308: [Zjoi2018]胖
5308: [Zjoi2018]胖 链接 分析: 题目转化为一个点可以更新多少个点,一个点可以更新的点一定是一个区间,考虑二分左右端点确定这个区间. 设当前点是x,向右二分一个点y,如果x可以更新到y ...
- P4501 [ZJOI2018]胖
题目 P4501 [ZJOI2018]胖 官方口中的送分题 做法 我们通过手玩(脑补),\(a_i\)所作的贡献(能更新的点)为:在\(a_i\)更新\(\forall x\)更新前前没有其他点能把\ ...
- zjoi[ZJOI2018]胖
题解: 因为n,m很大 所以复杂度应该是和m相关的 考虑到每个点的影响区间是连续的 就很简单了 区间查询最小值线段树维护(st表也可以) 然后注意一下不要重复算一个就可以了 max函数用templat ...
- ZJOI2018 胖 二分 ST表
原文链接https://www.cnblogs.com/zhouzhendong/p/ZJOI2018Day2T2.html 题目传送门 - BZOJ5308 题目传送门 - LOJ2529 题目传送 ...
- 2019.03.04 bzoj5308: [Zjoi2018]胖(二分答案+st表)
传送门 想题5分钟调题两小时系列 其实还是我tcl 读完题之后自然会知道一个关键点能够更新的点是一段连续的区间,于是我们对于每个点能到的左右区间二分答案,用ststst表维护一下查询即可. 代码: # ...
- BZOJ5308 ZJOI2018胖
贝尔福特曼(?)的方式相当于每次将所有与源点直接相连的点的影响区域向两边各扩展一格.显然每个点在过程中最多更新其他点一次且这些点构成一段连续区间.这个东西二分st表查一下就可以了.注意某一轮中两点都更 ...
- 洛谷P4501/loj#2529 [ZJOI2018]胖(ST表+二分)
题面 传送门(loj) 传送门(洛谷) 题解 我们对于每一个与宫殿相连的点,分别计算它会作为多少个点的最短路的起点 若该点为\(u\),对于某个点\(p\)来说,如果\(d=|p-u|\),且在\([ ...
- bzoj 5308: [Zjoi2018]胖
Description Cedyks是九条可怜的好朋友(可能这场比赛公开以后就不是了),也是这题的主人公. Cedyks是一个富有的男孩子.他住在著名的ThePLace(宫殿)中. Cedyks是一个 ...
随机推荐
- 12 Linux Which Command, Whatis Command, Whereis Command Examples
This Linux tutorial will explain the three "W" commands. The three "W"s are what ...
- 史上最全python面试题详解(三)(附带详细答案(关注、持续更新))
38.面向对象深度优先和广度优先是什么? 39.面向对象中super的作用? 40.是否使用过functools中的函数?其作用是什么? Python自带的 functools 模块提供了一些常用的高 ...
- linux查看用户、创建用户、设置密码、修改用户、删除用户命令
查看用户 /etc/passwd /etc/shadow id alex ' |passwd --stdin alex # 设置密码,不需要交互 [root@localhost ~]# tail -l ...
- 小tips:JS中this操作执行像(object.getName = object.getName)()操作改变了this
var name = "The window"; var object = { name: "My Object", getName: function(){ ...
- 页面间固定参数,通过cookie传值
最后在做的页面,比如用户数据(用户头像,名称,年龄)这些信息,因为大部分页面都要用,之前是通过url地址传,另一页面接收.考虑到这样做会让url过长,因此,尝试使用cookie,把固定的值保存在coo ...
- Node.js学习记录(一)--安装设置篇
安装Node window window上安装node可选择以下两种方式: 方式一:直接进入官网下载安装 进入node.js官网点击windows,选择.msi后缀的,根据自己的电脑选择对应的64位或 ...
- Keras实现VGG16
一.代码实现 # -*- coding: utf-8 -*- """ Created on Sat Feb 9 15:33:39 2019 @author: zhen & ...
- [20190213]学习bbed-恢复删除的数据.txt
[20190213]学习bbed-恢复删除的数据.txt --//以前也做过类似测试,当时在用bbed做verify时错误都不处理,当时的想法就是能读出就ok了.--//而且当时也做成功,纯粹是依葫芦 ...
- shell编程—变量(三)
在shell脚本中,变量分两种,系统变量和自定义变量. 系统默认变量是系统自带的一些变量,如path为路径变量 用户自定义变量为在编写吧脚本的时候自己定义的一些变量 变量名命名规则 首个字符必须为字母 ...
- 洗礼灵魂,修炼python(64)--爬虫篇—re模块/正则表达式(2)
前面学习了元家军以及其他的字符匹配方法,那得会用啊对吧?本篇博文就简单的解析怎么运用 正则表达式使用 前面说了正则表达式的知识点,本篇博文就是针对常用的正则表达式进行举例解析.相信你知道要用正则表达式 ...