【BZOJ 4299】 Codechef FRBSUM 主席树

来源:互联网 发布:澳门mac专柜 编辑:程序博客网 时间:2024/05/21 19:38

一个显然的性质:如果之前可以组成前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 longusing 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;}


0 0