专栏文章

题解:P11406 [RMI 2020] 零和 / Sum Zero

P11406题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@min589on
此快照首次捕获于
2025/12/01 20:46
3 个月前
此快照最后确认于
2025/12/01 20:46
3 个月前
查看原文
首先前面的部分和其他题解是相同的,即找到最小的 j>ij>i 使得 [i,j][i,j] 中存在一个零段。
这显然是可以倍增解决的,但是我们只能开 99 个 int 数组了。
所以 4 进制倍增就好了,时间复杂度 O(nlogn)O(n\log n)
CPP
#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ll=long long;
const int N=4e5+9;
const int lgN=9e0;

int a[N],f[N][lgN],n,q;

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];

	vector<ll> b(a,a+n+1);
	partial_sum(b.begin(),b.end(),b.begin());
	sort(b.begin(),b.end());
	b.erase(unique(b.begin(),b.end()),b.end());
	ll tmp=0;
	for(int i=0;i<=n;tmp+=a[++i]) a[i]=lower_bound(b.begin(),b.end(),tmp)-b.begin()+1;
	b.clear();
	b.shrink_to_fit();
	b.resize(n+1,n+1);
	for(int i=n;i>=0;i--) f[i][0]=b[a[i]],b[a[i]]=i;

	for(int k=0;k<lgN;k++) f[n+1][k]=n+1;
	for(int i=n;i>=0;i--) f[i][0]=min(f[i+1][0],f[i][0]);
	for(int k=1;k<lgN;k++){
		for(int i=0;i<=n;i++) f[i][k]=f[f[f[f[i][k-1]][k-1]][k-1]][k-1];
	}

	cin>>q;
	while(q--){
		int l,r;
		cin>>l>>r;
		
		l--;
		int ans=0;
		for(int k=lgN-1;~k;k--){
			while(f[l][k]<=r) l=f[l][k],ans+=1<<(k<<1);
		}

		cout<<ans<<endl;
	}

	return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...