Loj #2529. 「ZJOI2018」胖

题目描述

Cedyks 是九条可怜的好朋友(可能这场比赛公开以后就不是了),也是这题的主人公。

Cedyks 是一个富有的男孩子。他住在著名的 The Place(宫殿)中。

Cedyks 是一个努力的男孩子。他每天都做着不一样的题来锻炼他的 The Salt (灵魂)。这天,他打算在他的宫殿外围修筑一道城墙,城墙上有 \(n\) 座瞭望塔。你可以把城墙看做一条线段,瞭望塔是线段上的 \(n\) 个点,其中 \(1\) 和 \(n\) 分别为城墙的两个端点。其中第 \(i\) 座瞭望塔和第 \(i + 1\) 座瞭望塔的距离为 \(w_i\) ,他们之间的道路是双向的。

城墙很快就修建好了,现在 Cedyks 开始计划修筑他的宫殿到城墙的道路。因为这题的题目名称,Cedyks 打算用他的宫殿到每一个瞭望塔的最短道路之和来衡量一个修建计划。

现在 Cedyks 手上有 \(m\) 个设计方案,第 \(k\) 个设计方案会在宫殿和瞭望塔之间修建 \(T_k\) 条双向道路,第 \(i\) 条道路连接着瞭望塔 \(a_i\) ,长度为 \(l_i\) 。

计算到每一个瞭望塔的最短路之和是一个繁重的工程,本来 Cedyks 想用广为流传的 SPFA 算法来求解,但是因为他的 butter (缓冲区)实在是太小了,他只能转而用原始的贝尔福特曼算法来计算,算法的流程大概如下:

\1. 定义宫殿是 \(0\) 号点,第 \(i\) 个瞭望塔是 \(i\) 号点,双向边 \((u_i , v_ i , l_i)\) 为一条连接 \(u_i\) 和 \(v_i\) 的双向道路。令 \(d\) 为距离数组,最开始 \(d_0 = 0 , d_i = 10^{18} (i \in [1 , n])\) 。

\2. 令辅助数组 \(c = d\) 。依次对于每一条边 \((u_i , v_i , w_i)\) 进行增广,\(c_{u_i} = \min(c_{u_i} , d_{v_i} + w_i)\) , \(c_{v_i} = \min(c_{v_i} , d_{u_i} + w_i)\) 。

\3. 令 \(t\) 为 \(c\) 和 \(d\) 中不一样的位置个数,即令 $S = {i | c_i \ne d_i } $ ,则 \(t = |S|\) 。若 \(t = 0\) ,说明 \(d\) 就是最终的最短路,算法结束。否则令 \(d = c\) ,回到第二步。

因为需要计算的设计方案实在是太多了,所以 Cedyks 雇佣了一些人来帮他进行计算。为了避免这些人用捏造出来的数据偷懒,他定义一个设计方案的校验值为在这个方案上运行贝尔福特曼算法每一次进入第三步 \(t\) 的和。他会让好几个雇佣来的人计算同样的设计方案,并比对每一个人给出的校验值。

你是 Cedyks 雇佣来的苦力之一,聪明的你发现在这个情形下计算最短路的长度的和是一件非常简单的事情。但是寄人篱下不得不低头,你不得不再计算出每一个方案的校验值来交差。

输入格式

第一行输入两个整数 \(n,m\) ,表示瞭望塔个数和设计方案个数。

接下来一行 \(n-1\) 个数 \(w_i\) ,表示瞭望塔 \(i\) 和 \(i + 1\) 之间道路的长度。

接下来 \(m\) 行,每行描述一个设计方案。第一个整数 \(K\) 表示设计方案中的道路数量,接下来

\(K\) 个数对 \((a_i , l_i)\) 为一条宫殿到瞭望塔的边。

输出格式

对于每一个设计方案,输出一行一个整数表示校验值。

数据范围与提示

对于 \(100\%\) 的数据,保证每个设计方案 \(a_i\) 两两不同且 \(1 \le a_i \le n\) 。

对于 \(100\%\) 的数据,保证 \(1 \le w_i , l_i \le 10^9 , 1 \le \sum K \le 2 \times 10^5\) 。

\(\\\)

我们考虑计算每个\(a_i\)可以更新的点。每个\(a_i\)可以更新的点一定是一段连续的区间,所以我们就可以二分左端点和右端点。设\(pre_i\)为\(1\)号点到\(i\)号点的距离。

以左端点为例,假设二分的是\(x\),那么容易发现\([2*x-a_i,x]\)的节点会比\(a_i\)先更新\(x\),假设存在\(a_j\in[2*x-a_i,x]\)。设\(pre_i\)为\(1\)号点到\(i\)号点的距离,那么\(a_j\)就可能将\(x\)更新为\(pre_x-pre_{a_j}+l_j\),我们需要判断一下\(\min\{pre_x-pre_{a_j}+l_j\}\)与\(pre_{a_i}-pre_x+l_i\)的关系就可以知道是否合法了。找最小值可以先二分出端点然后用\(ST\)表,常数小一些。

还要注意\((x,a_i)\)中的点可能比\(a_i\)更优。假设这个点为\(a_j\),也就是\(pre_{a_j}-pre_x+l_j\leq pre_{a_i}-pre_x+l_i\Rightarrow pre_{a_j}+l_j\leq pre_{a_i}+l_i\),这个拿个单调队列就可以判了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 200005 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} int n,m,k;
ll w[N],pre[N]; struct road {
int a;
ll d;
bool operator <(const road &x)const {return a<x.a;}
}s[N]; int lg[N];
ll mnp[N][20],mns[N][20];
int L[N],R[N]; int Upp(int p) {
if(s[k].a<p) return k+1;
int l=1,r=k,mid;
while(l<r) {
mid=l+r>>1;
if(s[mid].a>=p) r=mid;
else l=mid+1;
}
return l;
} int Low(int p) {
if(s[1].a>p) return -1;
int l=1,r=k,mid;
while(l<r) {
mid=l+r+1>>1;
if(s[mid].a<=p) l=mid;
else r=mid-1;
}
return l;
} ll query(ll ST[N][20],int l,int r) {
int k=lg[r-l+1];
return min(ST[l][k],ST[r-(1<<k)+1][k]);
} bool chkl(int v,int p,ll d) {
if(v==p) return 1;
int L=Upp(2*p-v),R=Low(p);
if(L>R) return 1;
else return pre[p]+query(mnp,L,R)>pre[v]-pre[p]+d;
} void cal_l() {
static int st[N],top;
static int l,r,mid;
s[0].a=0;
st[top=0]=0;
for(int i=1;i<=k;i++) {
while(top>0&&s[st[top]].d+pre[s[st[top]].a]>s[i].d+pre[s[i].a]) top--;
l=s[st[top]].a+1,r=s[i].a;
while(l<r) {
mid=l+r>>1;
if(chkl(s[i].a,mid,s[i].d)) r=mid;
else l=mid+1;
}
L[i]=l;
st[++top]=i;
}
} bool chkr(int v,int p,ll d) {
if(v==p) return 1;
int L=Upp(p),R=Low(2*p-v-1);
if(L<=R&&query(mns,L,R)-pre[p]<=pre[p]-pre[v]+d) return 0;
int x=Low(2*p-v);
if(x==-1||s[x].a!=2*p-v) return 1;
return pre[p]-pre[v]+d<=pre[s[x].a]-pre[p]+s[x].d;
} void cal_r() {
static int st[N],top;
static int l,r,mid;
st[top=0]=k+1;
s[k+1].a=n+1;
for(int i=k;i>=1;i--) {
while(top>0&&s[st[top]].d-pre[s[st[top]].a]>s[i].d-pre[s[i].a]) top--;
l=s[i].a,r=s[st[top]].a-1;
while(l<r) {
mid=l+r+1>>1;
if(chkr(s[i].a,mid,s[i].d)) l=mid;
else r=mid-1;
}
R[i]=l;
st[++top]=i;
}
} int main() {
lg[1]=0;
for(int i=2;i<=200000;i++) lg[i]=lg[i>>1]+1;
n=Get(),m=Get();
for(int i=1;i<n;i++) w[i]=Get();
for(int i=2;i<=n;i++) pre[i]=pre[i-1]+w[i-1];
while(m--) {
k=Get();
for(int i=1;i<=k;i++) s[i].a=Get(),s[i].d=Get();
sort(s+1,s+1+k);
for(int i=1;i<=k;i++) {
mnp[i][0]=s[i].d-pre[s[i].a];
mns[i][0]=s[i].d+pre[s[i].a];
}
for(int j=1;j<=lg[k];j++) {
for(int i=1;i<=k;i++) {
if(i+(1<<j)-1<=k) {
mns[i][j]=min(mns[i][j-1],mns[i+(1<<j-1)][j-1]);
mnp[i][j]=min(mnp[i][j-1],mnp[i+(1<<j-1)][j-1]);
}
}
}
cal_l(),cal_r();
ll ans=0;
for(int i=1;i<=k;i++) {
ans+=R[i]-L[i]+1;
}
cout<<ans<<"\n";
}
return 0;
}

Loj #2529. 「ZJOI2018」胖的更多相关文章

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

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

  2. LOJ #2434. 「ZJOI2018」历史(LCT)

    题意 click here 题解 我们首先考虑答案是个什么样的东西, 不难 发现每个点可以单独计算它的贡献. 令每个点 \(i\) 崛起次数为 \(a_i\) . 假设一个点子树的 \(\sum a_ ...

  3. @loj - 2434@ 「ZJOI2018」历史

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的 ...

  4. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  5. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  6. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  7. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

  8. Loj #2542. 「PKUWC2018」随机游走

    Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...

  9. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

随机推荐

  1. 服务器部署Laravel

    安装lnmp环境 参考:简书 - Centos 7 下安装LNMP官方最新版 安装redis 参考:简书 - Centos 7下使用yum安装redis 安装nodejs npm nodejs分8.x ...

  2. 2019-11-29-win10-uwp-列表模板选择器

    原文:2019-11-29-win10-uwp-列表模板选择器 title author date CreateTime categories win10 uwp 列表模板选择器 lindexi 20 ...

  3. C# - VS2019调用AForge库实现调用摄像头拍照功能

    前言 作为一名资深Delphi7程序员,想要实现摄像头扫描一维码/二维码功能,发现所有免费的第三方库都没有简便的实现办法,通用的OpenCV或者ZXing库基本上只支持XE以上的版本,而且一维码的识别 ...

  4. DRF简易了解

    Drf框架 一丶API接口 # 为了在团队内部形成共识.防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少双方之间的合作成本. ...

  5. Redis入门学习(二):下载安装

    Linux操作系统 Download, extract and compile Redis with: $ wget http://download.redis.io/releases/redis-4 ...

  6. Ubuntu16.04的搭建l.2.t.p.d(宿舍访问公司内网)

    主要的实现步骤 openswan(ipsec) : 提供一个密钥 ppp :提供用户名和密码 xl2tpd : 提供L2TP服务 sysctl : 提供服务器内部转发 iptables : 提供请求从 ...

  7. mysql建库,建表,补列

    SET NAMES UTF8;DROP DATABASE IF EXISTS tmooc; CREATE DATABASE tmooc CHARSET=UTF8; USE tmooc;CREATE T ...

  8. 利用javascript动态加载头部出现点击事件与hover事件无效解决方法

    这里是利用es6的promise函数来异步加载,当HTML动态加载过去的HTML片段加载完毕再执行绑定事件的js代码: 具体过程如下 这里是用了jQuery框架的例子 $(function(){ // ...

  9. linux epoll,poll,select

    epoll函数用法,还有点poll和select 1,LT的epoll是select和poll函数的改进版. 特点是,读完缓冲区后,如果缓冲区还有内容的话,epoll_wait函数还会返回,直到把缓冲 ...

  10. (导航页)OpenStack-M版-双节点手工搭建-附B站视频

    ↓↓↓↓↓↓↓↓视频已上线B站↓↓↓↓↓↓↓↓ >>>>>>传送门 本次搭建采用双节点,离线源搭建, 配置如下 本次搭建采用2台4核4G的虚拟机,也可以改为2核4G ...