因为城墙是一条直线,所以很容易看出我们只需要考虑城堡到城墙的路
那么关键是求出一条城堡到城墙的路的贡献
把一条路的终点向左右走的边界拓展出来,然后用ST表辅助查询就好了
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=2e5+5;
const ll INF=1e18;
int n,m,t,k,lg[N];
ll d1[N],d2[N],len[N],d[N];
ll mx[N][20],mn[N][20];
struct E{int a;ll len;E(){}E(int _a,ll _len):a(_a),len(_len){}}e[N];
inline bool operator < (const E &a,const E &b){return a.a<b.a;}
inline int maxx(int a,int b){if(d1[a]==d1[b]) return a>b?a:b; return d1[a]>d1[b]?a:b;}
inline int minn(int a,int b){if(d2[a]==d2[b]) return a<b?a:b; return d2[a]<d2[b]?a:b;}
inline void init(){
sort(e+1,e+k+1);
for(int i=1;i<=k;i++){
d1[i]=d[e[i].a]-e[i].len,d2[i]=d[e[i].a]+e[i].len;
mx[i][0]=mn[i][0]=i;
}
for(int i=1;(1<<i)<=k;i++)
for(int j=1;j+(1<<i)-1<=k;j++){
mx[j][i]=maxx(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);
mn[j][i]=minn(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
}
}
inline int getmx(int l,int r){
int o=lg[r-l+1];
return maxx(mx[l][o],mx[r-(1<<o)+1][o]);
}
inline int getmn(int l,int r){
int o=lg[r-l+1];
return minn(mn[l][o],mn[r-(1<<o)+1][o]);
}
inline int high(int a,int b,int p){
ll resa=e[a].len+abs(d[p]-d[e[a].a]);
ll resb=e[b].len+abs(d[p]-d[e[b].a]);
if(resa!=resb) return resa<resb?a:b;
if(abs(e[a].a-p)!=abs(e[b].a-p))
return abs(e[a].a-p)<abs(e[b].a-p)?a:b;
return a<b?a:b;
}
inline bool check(int p,int kk){
int res=abs(e[kk].a-p),b=kk;
int l=lower_bound(e+1,e+k+1,E(p-res,0))-e;
int r=upper_bound(e+1,e+k+1,E(p+res,0))-e-1;
int mid=upper_bound(e+1,e+k+1,E(p,0))-e-1;
if(l<=mid) b=high(b,getmx(l,mid),p);
if(r>mid) b=high(b,getmn(mid+1,r),p);
return b==kk;
}
inline ll solve(){
ll ans=0;
for(int i=1;i<=k;i++){
int l=1,r=e[i].a,mid,L;
while(l<r)
if(check(mid=((l+r)>>1),i)) r=mid;
else l=mid+1;
L=l,l=e[i].a,r=n;
while(l<r)
if(check(mid=((l+r+1)>>1),i)) l=mid;
else r=mid-1;
ans+=(r-L+1);
}
return ans;
}
int main(){
for(int i=2;i<N;i++) lg[i]=lg[i>>1]+1;
n=read(),m=read();
for(int i=2;i<=n;i++)
d[i]=read(),d[i]+=d[i-1];
while(m--){
k=read();
for(int i=1;i<=k;i++)
e[i].a=read(),e[i].len=read();
init();
cout<<solve()<<"\n";
}
return 0;
}