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. App_Code下类无法引用问题

    App_Code 下创建的.cs文件仅仅是“内容”不是代码.设置文件为“编译”就可正常引用.

  2. C 数组、枚举类型enum

    传递数组给函数 告诉编译器函数要接受一个指针 skip //函数声明,数组的长度无需声明,因为编译器不会对形式参数进行边界检查 void myFunction(int param[]) //或者 vo ...

  3. django中视图函数中装饰器

    方法一 给指定方法加 from django.utils.decorators import method_decorator class xx(View): @method_decorator(装饰 ...

  4. python3的hashlib库sha256、pbkdf2_hmac、blake2b基本用法

    hashlib.sha256: import hashlib x = hashlib.sha256()x.update(b"asd")print("x_1 = " ...

  5. java 线程之线程状态

    Thread 类中的线程状态: public enum State { NEW,//新建 RUNNABLE,// 执行态 BLOCKED, //等待锁(在获取锁的池子里) WAITING,//等待状态 ...

  6. Linux性能调优 | 01 平均负载的理解和分析

    01 uptime命令 通常我们发现系统变慢时,我们都会执行top或者uptime命令,来查看当前系统的负载情况,比如像下面,我执行了uptime,系统返回的了结果. [root@lincoding ...

  7. 设置 WPF 的全球化语言

    https://stackoverflow.com/questions/7454024/setting-culture-en-in-globally-in-wpf-app Thread.Current ...

  8. Android RadioButton控件

    RadioButton   单选按钮 常用属性: text 文本 checked=“true” 默认选中 一组互斥的单选按钮要放在RadioGroup中.RadioGroup常用属性: orienta ...

  9. Django 练习班级管理系统四 -- 编辑班级

    修改 classes.html {% extends "layout.html" %} {% block css %} {% endblock %} {% block conten ...

  10. centos7 ntp server & samba

    最近公司内部一个需求:必须 Linux建个 ntp server ,并且 Windows可以net time \\ip 访问. 想要解决问题,还得解决前置问题. 服务器不能上网,无法直接访问外部 yu ...