题解:P11406 [RMI 2020] 零和 / Sum Zero
【数据删除】卡空间题。
思路
首先极小的和为零的区间总共只有 \(O(n)\) 个。可以直接预处理。
然后从询问右端点开始,每次贪心的取左端点最近的极小区间一定不劣。于是预处理出每个数左边的第一个极小区间左端点,求出每次询问对应的左端点集合,然后二分即可。
考虑如何求出每次询问的左端点集合。因为每个点决策固定,于是可以形成一棵树,直接在这颗树上 dfs,维护到根链即为所求。
于是把询问离线挂到右端点上即可。
实现细节
本题极为卡空间。实现时注意以下几点:
- 注意空间复用。
- dfs 会带来额外的空间开销。
- 不要用 STL。
- 由于 \(n\) 的值域仅为 \(4\times10^5\),可以考虑用 \(1\) 个 long long 表示 \(3\) 个值域为 \(n\) 的数。
代码
#include <bits/stdc++.h>
using namespace std;
constexpr int N=4e5+5;
int n,q,pre[N],rk[N],tot,cnt,top,i=1,a1[N],a2[N];
long long t[N],b[N];
void add(int x,int y){
pre[++cnt]=a1[x];
t[cnt]=y,a1[x]=cnt;
}
void dfs0(int p){
t[p]|=1ll<<40,rk[p]=++tot;
for(int i=a1[p];i;i=pre[i])dfs0(t[i]&((1<<20)-1));
}
void dfs(int p){
t[p]|=1ll<<40;
for(;i<=q&&(b[i]>>20&((1<<20)-1))==p;i++)a2[b[i]&((1<<20)-1)]=rk+top+1-lower_bound(rk+1,rk+top+1,b[i]>>40);
rk[++top]=p+1;
for(int i=a1[p];i;i=pre[i])dfs(t[i]&((1<<20)-1));
top--;
}
signed main(){
clock_t _st=clock();
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a2[i],a1[i]=a1[i-1];
if(1ll*a2[i-1]+a2[i]>INT_MAX)a1[i]++,a2[i]=1ll*a2[i-1]+a2[i]-INT_MAX-1;
else if(1ll*a2[i-1]+a2[i]<0)a1[i]--,a2[i]=1ll*a2[i-1]+a2[i]+INT_MAX+1;
else a2[i]=a2[i-1]+a2[i];
}
for(int i=1;i<=n;i++)t[i]=(INT_MAX+1ll)*a1[i]+a2[i];
sort(t+1,t+n+1);
for(int i=0;i<=n;i++){
int l=1,r=n;
while(l<r){
const int mid=l+r>>1;
if(t[mid]>=(INT_MAX+1ll)*a1[i]+a2[i])r=mid;
else l=mid+1;
}
a1[i]=r;
}
memset(t,-1,sizeof(t));
pre[0]=-1,t[a1[0]]=0;
for(int i=1;i<=n;i++)pre[i]=max(1ll*pre[i-1],t[a1[i]]),t[a1[i]]=i;
memset(a1,0,sizeof(a1));
for(int i=1;i<=n;i++)if(~pre[i])add(pre[i],i);
cin>>q;
for(int i=1;i<=q;i++){
long long l,r;cin>>l>>r;
b[i]=l<<40|r<<20|i;
}
for(int i=0;i<=n;i++)t[i]&=(1<<20)-1;
for(int i=0;i<=n;i++)if(!(t[i]>>40))dfs0(i);
sort(b+1,b+q+1,[](long long x,long long y){return rk[x>>20&((1<<20)-1)]<rk[y>>20&((1<<20)-1)];});
for(int i=0;i<=n;i++)t[i]&=(1<<20)-1;
for(int i=0;i<=n;i++)if(!(t[i]>>40))dfs(i);
for(int i=1;i<=q;i++)cout<<a2[i]<<'\n';
clock_t _ed=clock();
cerr<<(_ed-_st)*1.0/CLOCKS_PER_SEC<<'\n';
return 0;
}

浙公网安备 33010602011771号