Loading

神秘数 题解

这可以说是主席树的一个板子题,主要维护不同区间的不同值域的区间和。

我们设当前已经求出的区间为 \([1,x]\) ,那么对于能扩充这个区间的数一定符合 \(k\in[1,x+1]\) ,因为若 \(k>x+1\)\(x+1\) 没有数来合成,所以答案即为 \(x+1\)

不过严谨得来说,设 \(lst\) 为上次合成的最右边界, \(k \ge lst+1\) ,否则一个数可能会重复用多次。

所以可以有两种写法

int lst=0,now=0;
while(1) {
        int tmp=T.query(T.root[r],T.root[l-1],lst+1,now+1,1,sum);
        if (tmp) lst=now+1,now+=tmp;
	else break;
}

或者是

int now=0;
while(1) {
	int tmp=T.query(T.root[r],T.root[l-1],1,now+1,1,sum);
	if (tmp>now) now=tmp;
	else break;
}		

两种写法时间复杂度没有什么区别,都是 \(O(nlog_2(\sum_{i=1}^{n}a_i)+m(\text{区间和右界右移})log_2(\sum_{i=1}^{n}a_i))\)

但第二种常数会小很多,因为线段树区间求和,所求区间范围越大,分割的区间越少,所以常数会更小。实测真的会快不少。

\(AC \kern 0.4emCODE:\)

#include<bits/stdc++.h>
#define p(i) ++i
#define ri register int
using namespace std;
const int N=1e5+7;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;	
}
int n,num[N];
struct Seg{
	int root[N],tot;
	struct Segmenttree{
		int l,r;
		int sum;
	}T[N<<5];
	inline void up(int x) {T[x].sum=T[T[x].l].sum+T[T[x].r].sum;}
	inline int New(int pre) {T[p(tot)]=T[pre];return tot;} 
	inline void insert(int &x,int pre,int l,int r,int p) {
		x=New(pre);
		if (l==r) {T[x].sum+=p;return;}
		int mid=(l+r)>>1;
		if (p<=mid) insert(T[x].l,T[pre].l,l,mid,p);
		else insert(T[x].r,T[pre].r,mid+1,r,p);
		up(x);
	}
	inline int query(int x,int y,int l,int r,int lt,int rt) {
		if (T[x].sum==T[y].sum) return 0;
		if (l<=lt&&rt<=r) return T[x].sum-T[y].sum;
		int mid=(lt+rt)>>1,res=0;
		if (l<=mid) res+=query(T[x].l,T[y].l,l,r,lt,mid);
		if (r>mid) res+=query(T[x].r,T[y].r,l,r,mid+1,rt);
		return res;
	}
}T;
int main() {
	int sum=0;
	n=read();
	for (ri i(1);i<=n;p(i)) sum+=(num[i]=read());
	for (ri i(1);i<=n;p(i)) T.insert(T.root[i],T.root[i-1],1,sum,num[i]);
	int q=read();
	for (ri i(1);i<=q;p(i)) {
		int l=read(),r=read();
		int now=0;
		while(1) {
			int tmp=T.query(T.root[r],T.root[l-1],1,now+1,1,sum);
			if (tmp>now) now=tmp;
			else break;
		}
		printf("%d\n",now+1);
	}
	return 0;
}
posted @ 2021-04-14 10:05  ナンカエデ  阅读(83)  评论(0编辑  收藏  举报