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. 4、Ext.NET 1.7 官方示例笔记 - 树

    <%@ Page Language="C#" %> <%@ Import Namespace="System.Collections.Generic&q ...

  2. sql server 查看连接详情

    SELECT * FROM [Master].[dbo].[SYSPROCESSES] WHERE [DBID] IN ( SELECT [DBID] FROM [Master].[dbo].[SYS ...

  3. Flask-Cookies和Session

    目录 cookies session save_session的参数 session源码执行流程 请求第一次过来时 请求第二次进来 SecureCookieSession 签名算法 session的生 ...

  4. 如何搭建wordpress ,wecenter

    14.什么是LNMP架构 LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写.L指Linux,N指Nginx,M一般指MySQL,也可以指MariaDB,P一般指PHP,也可 ...

  5. 简单记录(css换行带点与不带点)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. i春秋暑期训练营丨渗透测试工程师开课啦

    每个人的夏天 都有专属的解锁方式 或来一次难忘的旅行 或躺在家里吹着空调吃西瓜 又或者是和小伙伴参加暑期训练营 i春秋暑期渗透测试工程师 报名通道已全部开启 为了保证课程质量,采取小班教学,每班仅限3 ...

  7. 软件设计师【软件工程:软件开发模型、XP极限编程十二最佳实践】

    一.软件开发模型 二.XP极限编程十二最佳实践

  8. MYSQL练习随笔

    解法练习 案例1.子查询练习 字段 说明film_id 电影idtitle 电影名称description 电影描述信息category_id 电影分类idname 电影分类名称last_update ...

  9. Linux上安装git

    Linux上安装git Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理. 而国外的GitHub和国内的Coding都是项目的托管平台.但是在使用Git工具的时候 ...

  10. VUE注册局部组件

    // 局部组件命名规范 /* 1文件夹名大驼峰 MyLocalBtn.vue 2 使用的时候 将驼峰转化为横杠 <my-local-btn></my-local-btn> */ ...