ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

主席树Ⅱ

2021-08-18 21:32:17  阅读:206  来源: 互联网

标签:right return int able wh 主席 define


神秘数

一道算是十分巧妙的题目。

与其它许多题目一样,一开始并不会想到用什么主席树,那些都只是后来用来做优化的东西。让我们来思考一下,假如给一个数列,然后只有一次询问的话应该怎么办?排一下序,然后从小到大扫描。从小往大扫描的过程中,如果当前可以表示的范围是 \([1,able]\) ,当前这个可利用的数是 \(now\) ,那么很容易可以得到,如果 \(able+1\)<\(now-1\) 的话加入一个新的数必然会导致 \([able+1,now-1]\) 的数无法表示,反之,就把 \(able\) 修改成 \(able+now\) 。然后就可以啦。

但这样似乎是 \(O(NlogN)\) 的算法,如果硬来的话,势必会导致算法成为 \(MNlogN\) 完全过不了。所以我们需要加速这个过程。一般来说,导致这种情况的根源就是它指针是一个一个往后挪的,这非常浪费时间(想起了 \(KMP\) 算法……),我们就可以想一下,如何加速这个过程。

上面也说了,一个元素 \(now\) 可以更新 \(able\) 的条件是 \(able+1\)<\(now-1\) ,也就是说 \(\forall now\in[1,able+1]\) 都可以更新 \(able\) ,相当于每次我们进行的操作就变成了 \(able=able+\sum{now\in[last,able+1]}\),其中 \(last\) 表示上一次的 \(able\) 这样是为了防止同一个元素被加很多次。

可证这样的算法是 \(MlogN^2\) 的。但这还只是静态问题,我们需要进行区间查询,而这种比较复杂的区间信息查询显然无法用线段树实现,要么用分块,要么用莫队离线求,要么用主席树,这里选用了主席树。然后就好办啦。

#include<cstdio>
//#define zczc
const int N=100010;
const int S=1e9;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}

#define lc t[wh].left
#define rc t[wh].right
#define mid (l+r>>1)
struct node{
	int left,right,data;
}t[N<<5];
int nodecnt;
inline void pushup(int wh){
	t[wh].data=t[lc].data+t[rc].data;
	return;
}
inline int change(int x,int l,int r,int pl){
	
	int wh=++nodecnt;
	lc=t[x].left,rc=t[x].right,t[wh].data=t[x].data;
	t[wh].data+=pl;
	if(l==r){
		return wh;
	}
	if(pl<=mid)lc=change(lc,l,mid,pl);
	else rc=change(rc,mid+1,r,pl);
	//pushup(wh);
	
	//printf("c:%d %d %d %d %d %d\n",x,wh,l,r,pl,t[wh].data);
	
	return wh;
}
inline int work(int lwh,int rwh,int l,int r,int wl,int wr){
	//printf("%d %d %d %d %d %d\n",lwh,rwh,l,r,wl,wr);
	if(wl>wr)return 0;
	if(t[rwh].data-t[lwh].data==0)return 0;
	if(wl<=l&&r<=wr)return t[rwh].data-t[lwh].data;
	int an=0;
	if(wl<=mid)an+=work(t[lwh].left,t[rwh].left,l,mid,wl,wr);
	if(wr>mid)an+=work(t[lwh].right,t[rwh].right,mid+1,r,wl,wr);
	return an;
}
#undef mid
#undef lc
#undef rc

int root[N],m,n;

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int s1,s2;
	read(m);
	for(int i=1;i<=m;i++){
		read(s1);
		root[i]=change(root[i-1],1,S,s1);
		//printf("now:%d\n",root[i]);
	}
	read(n);
	while(n--){
		read(s1);read(s2);
		int maxn=0,ans=0,sum=0;
		while(true){
			sum=work(root[s1-1],root[s2],1,S,maxn+1,ans+1);
			//printf("work:%d %d %d\n",maxn+1,ans+1,sum);
			if(sum==0)break;
			maxn=ans+1;ans+=sum;
		}
		printf("%d\n",ans+1);
	}
	
	return 0;
}

标签:right,return,int,able,wh,主席,define
来源: https://www.cnblogs.com/dai-se-can-tian/p/15158908.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有