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. C# 刷遍 Leetcode 面试题系列连载(3): No.728 - 自除数

    前文传送门: C#刷遍Leetcode面试题系列连载(1) - 入门与工具简介 C#刷遍Leetcode面试题系列连载(2): No.38 - 报数 系列教程索引 传送门:https://enjoy2 ...

  2. Java编程基础——数组和二维数组

    Java编程基础——数组和二维数组 摘要:本文主要对数组和二维数组进行简要介绍. 数组 定义 数组可以理解成保存一组数的容器,而变量可以理解为保存一个数的容器. 数组是一种引用类型,用于保存一组相同类 ...

  3. C# 常用类库(字符串处理,汉字首字母拼音,注入攻击,缓存操作,Cookies操作,AES加密等)

    十年河东,十年河西,莫欺少年穷 学无止境,精益求精 记录下字符串类库,方便今后查阅 主要包含了字符串解决,去除HTML,SQL注入攻击检测,IP地址处理,Cookies操作,根据身份证获取性别.姓名. ...

  4. css中的baseline

    这是css中的一个容易被人忽略的概念,今天在知乎上看到一个问题,这个问题应该是关于baseline,才去补习了一下关于baseline的知识,首先我来还原一下问题: <div style=&qu ...

  5. java--set,Collections,map

    set 特点: 无序, 不允许重复 没有索引 Set<String> set = new HashSet<String>(); set.add("hello" ...

  6. pid相关命令

    pidof 查找正在运行进程的进程号(pid)的工具 pidof - find the process ID of a running program 参数: -s 表示只返回1个 pid -x 表示 ...

  7. Red Hat安装虚拟带库

    1.安装五个包 # yum -y install lzo-devel sg3_utils lsscsi mtx mt-st mtx源码:http://sourceforge.net/ 2.下载最新版的 ...

  8. iOS - 常用宏定义和PCH文件知识点整理

    (一)PCH文件操作步骤演示: 第一步:图文所示: 第二步:图文所示: (二)常用宏定义整理: (1)常用Log日志宏(输出日志详细可定位某个类.某个函数.某一行) //=============== ...

  9. 基本SQL语句使用方法

    结构:增: create database 库名 charset 字符集: create table 表名称(字段名 类型 约束 ,字段名 类型 约束) not null 非空primary key ...

  10. 如何解决phpMyAdmin缺少mcrypt 扩展

    出现问题:在安装配置phpMyAdmin管理mysql数据库的时候,打开phpMyAdmin登录页面,出现下面的错误提示: 缺少 mcrypt 扩展.请检查 PHP 配置 以CentOS 6.0系统为 ...