Cedyks 是九条可怜的好朋友(可能这场比赛公开之后就不是了),也是这题的主人公。node
Cedyks 是一个富有的男孩子。他住在著名的The Place(宫殿)中。c++
Cedyks 是一个努力的男孩子。他天天都作着不同的题来锻炼他的The Salt(灵魂)。git
这天,他打算在他的宫殿外围修筑一道城墙,城墙上有 $ n $ 座瞭望塔。你能够把城墙看作一条线段,瞭望塔是线段上的 $ n $ 个点,其中 $ 1 $ 和 $ n $ 分别为城墙的两个端点。其中第 $ i $ 座瞭望塔和第 $ i+1 $ 座瞭望塔的距离为 $ w_i $ ,他们之间的道路是双向的。算法
城墙很快就修建好了,如今Cedyks 开始计划修筑他的宫殿到城墙的道路。由于这题的题目名称,Cedyks 打算用他的宫殿到每个瞭望塔的最短道路之和来衡量一个修建计划。数组
如今Cedyks 手上有 $ m $ 个设计方案,第 $ k $ 个设计方案会在宫殿和瞭望塔之间修建 $ T_k $ 条双向道路,第 $ i $ 条道路链接着瞭望塔 $ a_i $ ,长度为 $ l_i $ 。ide
计算到每个瞭望塔的最短路之和是一个繁重的工程,原本Cedyks 想用广为流传的SPFA算法来求解,可是由于他的butter(缓冲区)实在是过小了,他只能转而用原始的贝尔福特曼算法来计算,算法的流程大概以下:spa
$ 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) $ 。code
$ 3. $ 令 $ t $ 为 $ c $ 和 $ d $ 中不同位置个数,即令 $ S=\{i|c_i \neq d_i\} $ ,则 $ t=|S| $ 。若 $ t=0 $ ,说明 $ d $ 就是最终的最短路,算法结束。不然令 $ d=c $ ,回到第二步。blog
由于须要计算的设计方案实在是太多了,因此Cedyks 雇佣了一些人来帮他进行计算。为了不这些人用捏造出来的数据偷懒,他定义一个设计方案的校验值为在这个方案上运行贝尔福特曼算法每一次进入第三步 $ t $ 的和。他会让好几个雇佣来的人计算一样的设计方案,并比对每个人给出的校验值。
你是Cedyks 雇佣来的苦力之一,聪明的你发如今这个情形下计算最短路的长度的和是一件很是简单的事情。可是寄人篱下不得不低头,你不得再也不计算出每个方案的校验值来交差。
对于一个瞭望塔,他所能覆盖的必定是一段连续的区间,因此咱们能够经过二分找到它的左右端点。
对于一个端点 $x$ 它能被瞭望塔 $p$ 覆盖的条件是:
令 $p,x$ 的距离为 $d$
在 $[x-d,x+d]$ 的范围内没有其余瞭望塔到 $x$ 的距离小于 $p$ 到 $x$ 的距离。(等于的状况有特别处理,后文说明)。
那么意味着咱们要求一段连续区间内的瞭望塔到某个单点的距离的最小值,若是咱们令 $dis[x]$ 表示端点 $x$ 到 $1$ 的距离,那么瞭望塔到单点的距离等于 $|dis[p]-dis[x]|+l$ 。为了去掉绝对值,咱们对于瞭望塔在右的状况记录 $dis[p]+l$ ,并用 $st$ 表维护区间最小值。对于瞭望塔在左的状况记录 $dis[p]-l$ 维护区间最大值。
接下来对于距离相等的状况,首先若是是瞭望塔右侧的部分咱们能够优先选择距离最贴近瞭望塔的,也就是坐标小的,在左侧的类比。
若是对于在瞭望塔两边且到瞭望塔的坐标相等的,咱们能够规定选择小的那一边,这样就能保证只被选择一次。
#include<bits/stdc++.h> #define il inline #define LL long long #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=2e5+5; LL dis[N],v1[N],v2[N]; int n,m,k,Lg[N],st1[N][21],st2[N][21],p[N]; struct node{ int x,l; }t[N]; il int read(){ int x,f=1;char ch; _(!)ch=='-'?f=-1:f;x=ch^48; _()x=(x<<1)+(x<<3)+(ch^48); return f*x; } bool cmp(node t1,node t2){ return t1.x<t2.x; } il int Min(int t1,int t2){ if(v1[t1]==v1[t2])return t1<t2?t1:t2; return (v1[t1]<v1[t2])?t1:t2; } il int Max(int t1,int t2){ if(v2[t1]==v2[t2])return t1<t2?t2:t1; return (v2[t1]>v2[t2])?t1:t2; } il int getmn(int l,int r){ int k=Lg[r-l+1]; return Min(st1[l][k],st1[r-(1<<k)+1][k]); } il int getmx(int l,int r){ int k=Lg[r-l+1]; return Max(st2[l][k],st2[r-(1<<k)+1][k]); } il bool pd1(int x,int y){ int l=(x<<1)-p[y],r=y,mid; l=lower_bound(p+1,p+1+k,l)-p; mid=upper_bound(p+1,p+1+k,x)-p-1; LL len=abs(dis[p[y]]-dis[x])+t[y].l; if(l<=mid){ int t1=getmx(l,mid); if(dis[x]-v2[t1]<len)return 0; if(dis[x]-v2[t1]==len&&y!=t1){ if(abs(p[t1]-x)<abs(p[y]-x))return 0; if(abs(p[t1]-x)==abs(p[y]-x)&&t1<y)return 0; } } if(mid<r){ int t2=getmn(mid+1,r); if(v1[t2]-dis[x]<len)return 0; if(v1[t2]-dis[x]==len&&y!=t2){ if(abs(p[t2]-x)<abs(p[y]-x))return 0; if(abs(p[t2]-x)==abs(p[y]-x)&&t2<y)return 0; } } return 1; } il bool pd2(int x,int y){ int l=y,r=(x<<1)-p[y],mid; r=upper_bound(p+1,p+1+k,r)-p-1; mid=upper_bound(p+1,p+1+k,x)-p-1; LL len=abs(dis[p[y]]-dis[x])+t[y].l; if(l<=mid){ int t1=getmx(l,mid); if(dis[x]-v2[t1]<len)return 0; if(dis[x]-v2[t1]==len&&y!=t1){ if(abs(p[t1]-x)<abs(p[y]-x))return 0; if(abs(p[t1]-x)==abs(p[y]-x)&&t1<y)return 0; } } if(mid<r){ int t2=getmn(mid+1,r); if(v1[t2]-dis[x]<len)return 0; if(v1[t2]-dis[x]==len&&y!=t2){ if(abs(p[t2]-x)<abs(p[y]-x))return 0; if(abs(p[t2]-x)==abs(p[y]-x)&&t2<y)return 0; } } return 1; } int main() { n=read();m=read(); for(int i=2;i<=n;i++)dis[i]=dis[i-1]+read(),Lg[i]=Lg[i>>1]+1; for(int i=1;i<=m;i++){ k=read(); for(int i=1;i<=k;i++)t[i].x=read(),t[i].l=read(); sort(t+1,t+1+k,cmp); for(int i=1;i<=k;i++)p[i]=t[i].x; for(int i=1;i<=k;i++) v1[i]=t[i].l+dis[t[i].x],v2[i]=dis[t[i].x]-t[i].l; for(int i=1;i<=k;i++)st1[i][0]=i,st2[i][0]=i; for(int j=1;j<=Lg[k];j++)for(int i=1;i+(1<<j)-1<=k;i++) st1[i][j]=Min(st1[i][j-1],st1[i+(1<<(j-1))][j-1]), st2[i][j]=Max(st2[i][j-1],st2[i+(1<<(j-1))][j-1]); LL ans=0; for(int i=1;i<=k;i++){ int l=1,r=t[i].x,res=r; while(l<=r){ int mid=(l+r)>>1; if(pd1(mid,i))res=mid,r=mid-1; else l=mid+1; } int kk=res; l=t[i].x,r=n,res=l; while(l<=r){ int mid=(l+r)>>1; if(pd2(mid,i))res=mid,l=mid+1; else r=mid-1; } ans+=res-kk+1; } printf("%lld\n",ans); } return 0; }