洛谷P4501 [ZJOI2018] 胖
求出每个新修道路到达的瞭望塔 \(x\) 能更新到的区间 \([l_i,r_i]\),答案即为 \(\sum r_i-l_i+1\)。
发现区间的范围是可以二分出来的,考虑 \(x\) 是否能更新 \(p\),设 \(d=|x-p|\),若在区间 \([p-d,p+d]\) 中没有比 \(x\) 更优的瞭望塔,则 \(p\) 能被 \(x\) 更新。判定是否更优可以用 \(ST\) 表查询最值。
当两个点同时可以更新一个点时会算重,设下标小的点更优即可。
#include<bits/stdc++.h>
#define maxn 200010
#define inf 1000000000000000
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,k;
int lg[maxn];
ll w[maxn],st[2][maxn][20];
struct node
{
int pos;
ll v;
}e[maxn];
bool operator < (const node &a,const node &b)
{
return a.pos<b.pos;
}
void ST()
{
sort(e+1,e+k+1);
for(int i=1;i<=k;++i)
st[0][i][0]=e[i].v-w[e[i].pos],st[1][i][0]=e[i].v+w[e[i].pos];
for(int t=0;t<=1;++t)
for(int j=1;j<=17;++j)
for(int i=1;i+(1<<j)-1<=k;++i)
st[t][i][j]=min(st[t][i][j-1],st[t][i+(1<<(j-1))][j-1]);
}
ll query(int l,int r,int t)
{
if(l>r) swap(l,r);
l=lower_bound(e+1,e+k+1,(node){max(l,1),0})-e;
r=upper_bound(e+1,e+k+1,(node){min(r,n),0})-e-1;
if(l>r) return inf;
int len=lg[r-l+1];
return min(st[t][l][len],st[t][r-(1<<len)+1][len]);
}
bool check(int x,int p,int t)
{
if(x==p) return true;
ll v=query(x,x,t^1)+w[p]*(t?1:-1);
if(!t&&(v>=query(2*p-x+1,p,0)+w[p]||v>=query(p,x-1,1)-w[p])) return false;
if(t&&(v>=query(x+1,p,0)+w[p]||v>=query(p,2*p-x-1,1)-w[p])) return false;
return v-t<query(2*p-x,2*p-x,t)+w[p]*(t?-1:1);
}
int solve(int x,int t)
{
int l=t?x:1,r=t?n:x,pos=x;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(x,mid,t)) pos=mid,t?l=mid+1:r=mid-1;
else t?r=mid-1:l=mid+1;
}
return pos;
}
int main()
{
read(n),read(m),lg[0]=-1;
for(int i=1;i<=n;++i) lg[i]=lg[i>>1]+1;
for(int i=2;i<=n;++i) read(w[i]),w[i]+=w[i-1];
while(m--)
{
ll v=0;
read(k);
for(int i=1;i<=k;++i) read(e[i].pos),read(e[i].v);
ST();
for(int i=1;i<=k;++i) v+=solve(e[i].pos,1)-solve(e[i].pos,0)+1;
printf("%lld\n",v);
}
return 0;
}