bzoj 4299: Codechef FRBSUM 主席树

题目大意: ... 自己看
我们发现问题变成了给我们一些数,问我们最小的不能组合出来的数

由于是多次询问,我们理所当然地想到使用数据结构

首先对于这个问题我们有一个现成的解决方法:
  若\([1,n]\)之内的数都可以被表示,那么如果假如一个数\(x\)满足\((x \leq n+1)\)
  则把x加入后我们可以表示\([1,n+x]\)内的所有数
所以我们从小到大选择区间内的数字,设当前我们可以表示出\([1,n]\)之内的所有数
那么我们判断所有$ \le n+1\(的数的和是否\) \ge n=1\( 如果不满足,那说明我们求和的所有数都已经被加入到了集合中并且已经不存在这个一个x,那么\)ans = n+1$
如果满足,那说明存在一些 \(x == n+1\),(因为n一定在上次计算被计入)
那么我们就让\(n = sum\),即当前可以表示的区间为\([1,sum]\)

所以我们就依据这个原理迭代即可。

复杂度为\(O(nlogn + m*(玄))\)

注:不要忘了开\(long long\)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(ll &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline ll cat_max(const ll &a,const ll &b){return a>b ? a:b;}
inline ll cat_min(const ll &a,const ll &b){return a<b ? a:b;}
const ll maxn = 200010;
const ll maxnum = 1000000000;
struct Node{
	Node *ch[2];
	ll sum;
	void update(){
		sum = ch[0]->sum + ch[1]->sum;
	}
}*null,*root[maxn];
Node mem[maxn*20],*C;
inline void init(){
	C = mem;null = C++;
	null->ch[0] = null->ch[1] = null;
	null->sum = 0;root[0] = null;
}
Node* insert(Node *rt,ll l,ll r,ll pos){
	Node *p = C++;*p = *rt;
	if(l == r){
		p->sum += pos;
		return p;
	}
	ll mid = l+r >> 1;
	if(pos <= mid) p->ch[0] = insert(rt->ch[0],l,mid,pos);
	else p->ch[1] = insert(rt->ch[1],mid+1,r,pos);
	p->update();return p;
}
ll query(Node *p1,Node *p2,ll l,ll r,ll x){
	if(l > x) return 0;
	if(r <= x) return p2->sum - p1->sum;
	ll mid = l+r >> 1,ret = 0;
	ret += query(p1->ch[0],p2->ch[0],l,mid,x);
	if(x  > mid) ret += query(p1->ch[1],p2->ch[1],mid+1,r,x);
	return ret;
}
int main(){
	init();
	ll n;read(n);
	for(ll i=1,x;i<=n;++i){
		read(x);
		root[i] = insert(root[i-1],1,maxnum,x);
	}
	ll m;read(m);
	ll s,t;
	while(m--){
		read(s);read(t);
		ll nw = 1,la = -1;
		while(1){
		//	la = nw;
			ll x = query(root[s-1],root[t],1,maxnum,nw);
		//	printf("query :: %d get : %d\n",nw,x);
			if(x >= nw) nw = x+1;
			else break;
		//	if(nw == la) break;
		}
		printf("%lld\n",nw);
	}
	getchar();getchar();
	return 0;
}
  
posted @ 2017-01-23 17:47  Sky_miner  阅读(312)  评论(0编辑  收藏  举报