BZOJ传送门
洛谷传送门
解析:
ZJOI2018对我现阶段而言唯一一道可做的题。(剩下全是神仙题做之前先%jiry_2)
我们发现这个图长得很有特点,而且Bellman-Ford第一步肯定是更新直接连接的那些节点。然后再在链上扩展。
现在考虑一个点与 0 0 0有边的点 u u u,它能够更新的显然是包含它的一个连续区间,我们需要考虑求出这个区间的左右端点 l , r l,r l,r,那么就能够得到它更新的区间长度就是 r − l + 1 r-l+1 r−l+1。
u u u能够更新 v v v的条件也很显然,设 l = ∣ u − v ∣ l=|u-v| l=∣u−v∣,则 u u u应该是 [ v − l , v + l ] [v-l,v+l] [v−l,v+l]中的特殊点中到 v v v最近的。当然我们还要考虑相等距离取坐标差小的问题。
显然我们可以根据 u u u在 v v v的哪边进行分类讨论。设 v a l u val_u valu是 0 0 0到 u u u的距离, d i s t u dist_u distu是链上 u u u到 1 1 1的距离,用于差分。
d i s ( u , v ) = { v a l u − u + v u ≤ v v a l u + u − v v < u dis(u,v)=\left\{\begin{aligned}val_u-u+v &&u \leq v\\val_u+u-v &&v< u\end{aligned}\right. dis(u,v)={valu−u+vvalu+u−vu≤vv<u
维护两个ST表就行了。
不开O2的话就不要用lower_bound和upper_bound了,手写吧。
不过开了O2就没什么区别了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=2e5+5,logN=18;
int n,m,K;
struct edge{
int to,dis;
bool operator<(cs edge &b)cs{
return to<b.to;
}
}e[N],tmp;
namespace ST{
ll l[logN][N],r[logN][N];
int logn[N];
inline void init(){
for(int re i=1;i<=logn[K];++i){
for(int re j=1;(1<<i)+j-1<=K;++j){
l[i][j]=min(l[i-1][j],l[i-1][j+(1<<(i-1))]);
r[i][j]=min(r[i-1][j],r[i-1][j+(1<<(i-1))]);
}
}
}
inline ll query_l(cs int &L,cs int &R){
int len=logn[R-L+1];
return min(l[len][L],l[len][R-(1<<len)+1]);
}
inline ll query_r(cs int &L,cs int &R){
int len=logn[R-L+1];
return min(r[len][L],r[len][R-(1<<len)+1]);
}
inline int lower_bound(cs int &a){
int l=1,r=K+1;
while(l<r){
int mid=(l+r)>>1;
if(e[mid].to<a)l=mid+1;
else r=mid;
}
return l;
}
inline int upper_bound(cs int &a){
int l=1,r=K+1;
while(l<r){
int mid=(l+r)>>1;
if(e[mid].to<=a)l=mid+1;
else r=mid;
}
return l;
}
inline ll Ql(int u,int v){
u=max(1,u),v=min(v,n);
u=lower_bound(u);
v=upper_bound(v)-1;
if(u>v)return 0x3f3f3f3f3f3f3f3f;
return query_l(u,v);
}
inline ll Qr(int u,int v){
u=max(1,u),v=min(v,n);
u=lower_bound(u);
v=upper_bound(v)-1;
if(u>v)return 0x3f3f3f3f3f3f3f3f;
return query_r(u,v);
}
}
ll dist[N],ans;
inline bool check_L(int u,int pos){
if(u==pos)return true;
ll mpt=ST::Qr(u,u)-dist[pos];
ll d1=ST::Qr(pos,u-1)-dist[pos];
ll d2=ST::Ql(2*pos-u+1,pos)+dist[pos];
if(d1<=mpt||d2<=mpt)return false;
if(2*pos-u>0)return ST::Ql(2*pos-u,2*pos-u)+dist[pos]>mpt;
return true;
}
inline bool check_R(int u,int pos){
if(u==pos)return true;
ll mpt=ST::Ql(u,u)+dist[pos];
ll d1=ST::Ql(u+1,pos)+dist[pos];
ll d2=ST::Qr(pos,2*pos-u-1)-dist[pos];
if(d1<=mpt||d2<=mpt)return false;
if(2*pos-u<=n)return ST::Qr(2*pos-u,2*pos-u)-dist[pos]>=mpt;
return true;
}
inline int find_L(int u){
int l=1,r=u;
while(l<r){
int mid=(l+r)>>1;
if(check_L(u,mid))r=mid;
else l=mid+1;
}
return l;
}
inline int find_R(int u){
int l=u,r=n,ans=u;
while(l<=r){
int mid=(l+r+1)>>1;
if(check_R(u,mid))l=mid+1,ans=mid;
else r=mid-1;
}
return ans;
}
signed main(){
n=getint(),m=getint();
for(int re i=2;i<=n;++i)ST::logn[i]=ST::logn[i>>1]+1;
for(int re i=2;i<=n;++i)dist[i]=dist[i-1]+getint();
while(m--){
K=getint();
for(int re i=1;i<=K;++i)e[i].to=getint(),e[i].dis=getint();
sort(e+1,e+K+1);
for(int re i=1;i<=K;++i){
ST::l[0][i]=e[i].dis-dist[e[i].to];
ST::r[0][i]=e[i].dis+dist[e[i].to];
}
ST::init();
ans=0;
for(int re i=1;i<=K;++i)
ans+=find_R(e[i].to)-find_L(e[i].to)+1;
cout<<ans<<'\n';
}
return 0;
}