[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是一个 ...
随机推荐
- Mac下写博客工具MarsEdit相关资料
参考资料: https://www.maoshu.cc/967.html 下载地址: https://www.red-sweater.com/marsedit/ 博客园的配置: http://www. ...
- js动画 Css提供的运动 js提供的运动
1. 动画 (1) Css样式提供了运动 过渡的属性transition 从一种情况到另一种情况叫过渡 Transition:attr time linear delay: ...
- C#设计模式之十三模板方法模式(Template Method Pattern)【行为型】
一.引言 “结构型”的设计模式已经写完了,从今天我们开始讲“行为型”设计模式.现在我们开始讲[行为型]设计模式的第一个模式,该模式是[模板方法],英文名称是:Template Method Patte ...
- js之单例模式
单例模式是指一个类,只有一个实例.实现的思路是,创建实例时候加判断,如果有实例则返回,如果没有就new一个,并返回. 第一步: 创建类. function Waiter(id, name, salar ...
- JS之汉字与Unicode码的相互转化
有时候,我们在给后端传递变量的的值中有汉字,可能由于编码的原因,传递到后端后变为乱码了.所以有时候为了省事或者其它特殊要求的时候,会把传递的汉字转换成Unicode编码后再进行传递. 当然汉字转换成u ...
- iOS--------获取当前连接的WiFi以及IP地址
导入头文件 #import <ifaddrs.h>#import <arpa/inet.h>#import <SystemConfiguration/CaptiveNet ...
- Android项目实战(五十):微信支付 坑总结
大部分APP必备需求,使用总结 Android接入文章在此:官方文档 文档很简单,Android分为四步: 1.后台配置 2.Android 内 注册appId 3.Android 内 调起支付 4. ...
- js导出Excel表格
js导出Excel表格 直接上代码: 红色部分:如果表格数据中有“1/1”这样的值,会在导出的Excel中转化为日期“1月1日”,所以才加上了红色那两句.如果返回值中没有这样的格式,红色部分可以不写. ...
- Codeup
问题 I: 习题5-10 分数序列求和 时间限制: 1 Sec 内存限制: 12 MB提交: 611 解决: 537[提交][状态][讨论版][命题人:外部导入] 题目描述 有如下分数序列 求出次 ...
- leetcode-67.二进制求和
leetcode-67.二进制求和 Points 数组 数学 题意 给定两个二进制字符串,返回他们的和(用二进制表示). 输入为非空字符串且只包含数字 1 和 0. 示例 1: 输入: a = &qu ...