贝尔福特曼是什么算法?那不应该是spafspafspaf吗?
考虑对一个点xxx总共可以松弛多少个点
显然xxx可以松弛是一段连续的区间[L,R][L,R][L,R]
发现不好维护可以松弛到哪里
考虑二分一个位置midmidmid,判定是否能被松弛
假设二分一个mid(mid>x)mid(mid>x)mid(mid>x)
显然会影响xxx对midmidmid松弛只有可能是[x,2∗x−mid][x,2*x-mid][x,2∗x−mid]这段区间的关键点
如果存在点yyy满足disy,mid+a[y]≤disx,mid+a[x]dis_{y,mid}+a[y]\le dis_{x,mid}+a[x]disy,mid+a[y]≤disx,mid+a[x]
若记一个前缀距离和即sumy+a[y]≤sumx+a[x]sum_y+a[y]\le sum_{x}+a[x]sumy+a[y]≤sumx+a[x]
那考虑对于每一个关键点维护sumx+a[x]sum_x+a[x]sumx+a[x],那只需要查找在区间是否有更小的数
对关键点建一个ststst表就可以了
注意二分是在原序列上二分,而ststst表是在kkk个关键点上
所以每次ststst表要先二分在哪2个关键点之间
复杂度O(nlog2n)O(nlog^2n)O(nlog2n)
有点卡常
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int read() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
#define ll long long
#define re register
const int N=200005;
const ll inf=1e18;
struct node{
int p;ll k;
node(int _p=0,ll _k=0):p(_p),k(_k){}
friend inline bool operator <(const node &a,const node &b){
return a.p<b.p;
}
}a[N];
int n,m,k,lg[N],val[N];
ll ans,dis[N];
struct ST{
ll st[20][N];
inline void init(){
for(re int i=1;i<=k;++i)st[0][i]=a[i].k;
for(re int j=1;j<=lg[k];++j){
for(re int i=1;i+(1<<j)-1<=k;++i)
st[j][i]=min(st[j-1][i],st[j-1][i+(1<<(j-1))]);
}
}
inline ll query(int l,int r){
l=max(l,1),r=min(r,n);
l=lower_bound(a+1,a+k+1,node(l))-a;
r=upper_bound(a+1,a+k+1,node(r))-a-1;
if(l>r)return inf;
int t=lg[r-l+1];
return min(st[t][l],st[t][r-(1<<t)+1]);
}
}L,R;
inline bool check1(int l,int r){
if(l==r)return 1;
ll r1=L.query(2*l-r+1,l)+dis[l];
ll r2=R.query(l,r-1)-dis[l];
ll r3=R.query(r,r)-dis[l];
if(r1<=r3||r2<=r3)return false;
if(2*l-r>=1)return L.query(2*l-r,2*l-r)+dis[l]>=r3;
return true;
}
inline bool check2(int l,int r){
if(l==r)return 1;
ll r1=R.query(r,2*r-l-1)-dis[r];
ll r2=L.query(l+1,r)+dis[r];
ll r3=L.query(l,l)+dis[r];
if(r1<=r3||r2<=r3)return false;
if(2*r-l<=n)return R.query(2*r-l,2*r-l)-dis[r]>r3;
return true;
}
inline int solve1(int p){
int l=1,r=p,mid,res=0;
while(l<=r){
mid=(l+r)>>1;
if(check1(mid,p))r=mid-1,res=mid;
else l=mid+1;
}
return res;
}
inline int solve2(int p){
int l=p,r=n,mid,res=0;
while(l<=r){
mid=(l+r)>>1;
if(check2(p,mid))l=mid+1,res=mid;
else r=mid-1;
}
return res;
}
int main(){
n=read(),m=read();
for(re int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
for(re int i=2;i<=n;++i)val[i]=read(),dis[i]=dis[i-1]+val[i];
while(m--){
k=read();
for(re int i=1;i<=k;++i)a[i].p=read(),a[i].k=read();
sort(a+1,a+k+1),ans=0;
for(re int i=1;i<=k;++i)a[i].k-=dis[a[i].p];L.init();
for(re int i=1;i<=k;++i)a[i].k+=2*dis[a[i].p];R.init();
for(re int i=1;i<=k;++i)ans+=solve2(a[i].p)-solve1(a[i].p)+1;
cout<<ans<<'\n';
}
}