【BZOJ 4299】 Codechef FRBSUM 主席树

236 篇文章 0 订阅
15 篇文章 0 订阅

一个显然的性质:如果之前可以组成前mx个数,那么可以新加入一个<=mx+1的数构成一个更大的mx,如果>max+1则对当前无贡献

但是。。。推出这个性质后面我就没想到了。。。。

其实,每当我们得到一个mx以后,因为小于等于mx+1的数都可以和mx构成一个新的mx,因此新的mx=sum[mx+1],sum表示小于等于mx+1的前缀和,而这样每一次都至少增加一倍所以最多log次,主席树维护前缀和就好了

#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 100021
#define LL long long
using namespace std;
int n,m,ls[maxn*40],rs[maxn*40],tot,rt[maxn];
LL sum[maxn*40];
void insert(int x,int& y,int l,int r,int id){
	y=++tot;ls[y]=ls[x],rs[y]=rs[x];sum[y]=sum[x]+id;
	if(l==r)return;
	int mid=l+r>>1;
	if(id>mid)insert(rs[x],rs[y],mid+1,r,id);
	else insert(ls[x],ls[y],l,mid,id);
}
LL query(int x,int y,int l,int r,int id){
	if(l==r)return sum[y]-sum[x];
	int mid=l+r>>1;
	if(id<=mid)return query(ls[x],ls[y],l,mid,id);
	else return sum[ls[y]]-sum[ls[x]]+query(rs[x],rs[y],mid+1,r,id);
}
int main(){
	scanf("%d",&n);
	for(int x,i=1;i<=n;i++){
		scanf("%d",&x);
		insert(rt[i-1],rt[i],1,1e9,x);
	}scanf("%d",&m);int l,r;LL mx,last;
	while(m--){
		scanf("%d%d",&l,&r);
		mx=last=0;
		while(1){
			mx=query(rt[l-1],rt[r],1,1e9,mx+1);
			if(mx==last){printf("%lld\n",mx+1);break;}
			last=mx;
		}
	}return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值