【BZOJ5308】[ZJOI2018]胖(模拟,ST表,二分)

题面

BZOJ

洛谷

题解

首先发现每条\(0\)出发的边都一定会更新到底下的一段区间的点。

考虑存在一条\(0\rightarrow x\)的边,我们来求解其可以影响的区间\([L,R]\),显然\(L\le x\le R\)。

两侧分开考虑,以左边举例。

二分一个\(L\)。如果这个\(L\)可行,即不存在一条边\(0\rightarrow y\),满足\(W_{0\rightarrow x}+Dis(L,x)\ge W_{0\rightarrow y}+Dis(L,y)\),且\(abs(y-L)\le abs(x-L)\)。

也就是要么\(x\)出发能够更新最短路,要么就是\(x\)离\(L\)更近,所以先被\(x\)的路径更新了一次。

那么对于二分出来的\(L\),令\(len=|x-L|\),如果在\([L-len,L+len]\)区间内存在一个点能够更新出更小的距离则当前\(L\)不可行。\(R\)同理。

然后大力\(ST\)表二分一下就好了。

注意一下如果一个点可以同时被多个点更新的时候,一定要确定好一个顺序关系,使得最终计算出来的结果不重不漏。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 200200
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,Q,k,lg[MAX];
ll w[MAX],v1[MAX],v2[MAX];
ll mn[20][MAX],mx[20][MAX];
struct Line{int x,w;}a[MAX];
bool operator<(Line a,Line b){return a.x<b.x;}
int Max(int x,int y)
{
if(v1[x]!=v1[y])return v1[x]>v1[y]?x:y;
if(a[x].x!=a[y].x)return a[x].x>a[y].x?x:y;
return x<y?x:y;
}
int Min(int x,int y)
{
if(v2[x]!=v2[y])return v2[x]<v2[y]?x:y;
if(a[x].x!=a[y].x)return a[x].x<a[y].x?x:y;
return x<y?x:y;
}
void pre()
{
for(int i=1;i<=k;++i)
v1[i]=w[a[i].x]-a[i].w,v2[i]=w[a[i].x]+a[i].w;
for(int i=1;i<=k;++i)mx[0][i]=mn[0][i]=i;
for(int j=1;j<=lg[k];++j)
for(int i=1;i+(1<<j)-1<=k;++i)
{
mx[j][i]=Max(mx[j-1][i],mx[j-1][i+(1<<(j-1))]);
mn[j][i]=Min(mn[j-1][i],mn[j-1][i+(1<<(j-1))]);
}
}
ll RMQ_mx(int l,int r)
{
int k=lg[r-l+1];
return Max(mx[k][l],mx[k][r-(1<<k)+1]);
}
ll RMQ_mn(int l,int r)
{
int k=lg[r-l+1];
return Min(mn[k][l],mn[k][r-(1<<k)+1]);
}
bool check(int x,int l,int y)
{
int p=lower_bound(&a[1],&a[k+1],(Line){y-l,0})-a;
int q=upper_bound(&a[1],&a[k+1],(Line){y+l,0})-a-1;
int r=lower_bound(&a[1],&a[k+1],(Line){y,0})-a;
if(r<=q)
{
int pos=RMQ_mn(r,q);ll V=abs(w[a[x].x]-w[y])+a[x].w;
if(v2[pos]-w[y]<V||(v2[pos]-w[y]==V&&abs(a[pos].x-y)<abs(a[x].x-y))
||(v2[pos]-w[y]==V&&abs(a[pos].x-y)==abs(a[x].x-y)&&pos<x))
return false;
}
if(p<r)
{
int pos=RMQ_mx(p,r-1);ll V=abs(w[a[x].x]-w[y])+a[x].w;
if(w[y]-v1[pos]<V||(w[y]-v1[pos]==V&&abs(a[pos].x-y)<abs(y-a[x].x))
||(w[y]-v1[pos]==V&&abs(a[pos].x-y)==abs(a[x].x-y)&&pos<x))
return false;
}
return true;
}
int GetL(int x)
{
int l=1,r=a[x].x,ret=a[x].x;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(x,a[x].x-mid,mid))ret=mid,r=mid-1;
else l=mid+1;
}
return ret;
}
int GetR(int x)
{
int l=a[x].x,r=n,ret=a[x].x;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(x,mid-a[x].x,mid))ret=mid,l=mid+1;
else r=mid-1;
}
return ret;
}
ll Solve()
{
k=read();for(int i=1;i<=k;++i)a[i].x=read(),a[i].w=read();
sort(&a[1],&a[k+1]);
pre();ll ans=0;
for(int i=1;i<=k;++i)
{
ans+=GetR(i)-GetL(i)+1;
}
return ans;
}
int main()
{
n=read();Q=read();
for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
for(int i=2;i<=n;++i)w[i]=read()+w[i-1];
while(Q--)printf("%lld\n",Solve());
return 0;
}

【BZOJ5308】[ZJOI2018]胖(模拟,ST表,二分)的更多相关文章

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

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

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

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

  3. BZOJ5308 ZJOI2018胖

    贝尔福特曼(?)的方式相当于每次将所有与源点直接相连的点的影响区域向两边各扩展一格.显然每个点在过程中最多更新其他点一次且这些点构成一段连续区间.这个东西二分st表查一下就可以了.注意某一轮中两点都更 ...

  4. 【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分

    4310: 跳蚤 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 180  Solved: 83[Submit][Status][Discuss] De ...

  5. BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html 题目传送门 - BZOJ4556 题意 给定一个长度为 $n$ 的字符串 $s$ . ...

  6. hdu5289 ST表+二分

    用裸的St表+暴力枚举查询时稳TLE的,可以枚举每个区间的起点+二分满足条件的区间右端,这样复杂度是O(nlogn) #include<iostream> #include<cstr ...

  7. luoguP5108 仰望半月的夜空 [官方?]题解 后缀数组 / 后缀树 / 后缀自动机 + 线段树 / st表 + 二分

    仰望半月的夜空 题解 可以的话,支持一下原作吧... 这道题数据很弱..... 因此各种乱搞估计都是能过的.... 算法一 暴力长度然后判断判断,复杂度\(O(n^3)\) 期望得分15分 算法二 通 ...

  8. 2016多校联合训练1 D题GCD (ST表+二分)

    暑假颓废了好久啊...重新开始写博客 题目大意:给定10w个数,10w个询问.每次询问一个区间[l,r],求出gcd(a[l],a[l+1],...,a[r])以及有多少个区间[l',r']满足gcd ...

  9. GCD(st表+二分)

    GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...

  10. ZSTU 4241 圣杯战争(ST表+二分)

    题目链接  ZSTU 4241 问题转化为有很多区间,现在每次给定一个区间求这个区间和之前所有区间中的某一个的交集的最大长度. 强制在线. 首先我们把所有的区间预处理出来. 然后去重(那些被包含的小区 ...

随机推荐

  1. 记第一次多用户在Git提交代码

    今天第一次进行了多用户(其实就两人)在自建Git服务器提交代码. 先记录碰到的问题:首先是本地提交代码时,进行了add,commit后,在push时碰到服务器故障,待设置好服务器后,再push时,却p ...

  2. JavaScript实现文字跑马灯

    其实实现文字的跑马灯和实现图片轮播的原理是一样的. 下面是我自己实现的,文字的位置可以随便更改,效果不会变,文字的内容可以通过ajax获取,同时,可以直接用Jquery改写一下,很方便. <!D ...

  3. shell脚本--初识CGI

    CGI按照百度百科的定义,如下: CGI 是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能.CGI 应用程序能与浏览器进行交互,还可通过数据库API 与数据库服务器等外部数 ...

  4. PHP之常用设计模式

    在日常开放中,经常会用到一些设计模式,进行我们代码的优化处理,一个很好的设计思想 1) 工厂模式 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象 ...

  5. 【Python3练习题 014】 一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如6=1+2+3。编程找出1000以内的所有完数。

    a.b只要数字a能被数字b整除,不论b是不是质数,都算是a的因子.比如:8的质因子是 2, 2, 2,但8的因子就包括 1,2,4. import math   for i in range(2, 1 ...

  6. Git命令以及常见注意事项

    命令: git init -> 初始化一个git仓库 git clone -> 克隆一个本地库 git pull -> 拉取服务器最新代码 git fetch –p -> 强行 ...

  7. [转帖]PAT 计算机程序设计能力考试

    PAT 计算机程序设计能力考试 https://blog.csdn.net/bat67/article/details/52134211 [官方简介] 计算机程序设计能力考试(Programming ...

  8. Linux(CentOS7)命令学习摘要

    1. 修改机器名 hostnamectl set-hostname newname 2. hosts主机存放位置 /etc/hosts 3. 安装tigervncserver, 然后使用vncserv ...

  9. Android常用的技术框架与博客社区

    技术框架 图片加载 Glide Fresco Volley Picasso Universal Image Loader 网络请求 okhttp retrofit Volley android-asy ...

  10. python之路--MySQL多表查询

    一 介绍 我们在写项目的时候一般都会建一个数据库,数据库里面会存很多的表,不可能把所有的数据都放在一张表里,因为分表来存数据节省空间,数据的组织结构更清晰,解耦和程度更高,但是这些表本质上还不是一个整 ...