POJ-2104 K-th Number

1.题面

http://poj.org/problem?id=2104

2.题意

给定一个序列a,求a[l----r]之间的第k大值

3.思路

听说要用主席树做,我暂时还不会,用zkw线段树写了一个,然后普通线段树过了,zkw线段树tle了,更确切地说是POJ没法过,其他OJ如SPOJ上过了,那样的话,思路应该没有问题了

新补了一个主席树的做法

4.代码

zkw线段树

/*****************************************************************
    > File Name: Cpp_Acm.cpp
    > Author: Uncle_Sugar
    > Mail: uncle_sugar@qq.com
    > Created Time: 2016年07月18日 星期一 21时59分32秒
*****************************************************************/
# include <cstdio>
# include <vector>
# include <algorithm>
using namespace std;

const int size  = 300000 + 10; 

int n,m;
vector<int> T[2*size];
int sz;

void Build(int n){
	for (sz=1;sz<n+2;sz<<=1);
	int i = 0;
	for (i=sz+1;i<=sz+n;i++){
		T[i].clear();	
		int tmp;
		scanf("%d",&tmp);
		T[i].push_back(tmp);
	}
	for (i=sz-1;i>=1;i--){
		T[i].resize(T[i<<1].size()+T[i<<1|1].size());		
		merge(T[i<<1].begin(),T[i<<1].end(),T[i<<1|1].begin(),T[i<<1|1].end(),T[i].begin());
	}
}

int Query(int s,int t,int x){
	int ret = 0;
	for (s=s+sz-1,t=t+sz+1;s^t^1;s>>=1,t>>=1){
		if (~s&1) ret += upper_bound(T[s^1].begin(),T[s^1].end(),x) - T[s^1].begin();	
		if (t&1)  ret += upper_bound(T[t^1].begin(),T[t^1].end(),x) - T[t^1].begin();
	}
	return ret;
}

int main()
{
	int i,j;
	while (~scanf("%d%d",&n,&m)){
		Build(n);	
		while (m--){
			int l,r,k;
			scanf("%d%d%d",&l,&r,&k);
			int lb = 0,rb = n-1,mid;	
			while (lb < rb){
				mid = lb+rb>>1;
				int x = Query(l,r,T[1][mid]);
				if (x<k) lb = mid + 1;
				else rb = mid;
			}
			printf("%d\n",T[1][rb]);
		}
	}
	return 0;
}


主席树

# include <cstdio>
# include <cstring>
# include <cctype>
# include <cmath>
# include <cstdlib>
# include <climits>
# include <iostream>
# include <iomanip>
# include <set>
# include <map>
# include <vector>
# include <stack>
# include <queue>
# include <algorithm>
using namespace std;

const int debug = 1;
const int size  = 3000000 + 10; 
const int INF = INT_MAX>>1;
typedef long long ll;

int lson[size],rson[size];
int data[size];
int tot = 0;
int T[size];

int n,m;
int num[size],h[size];
int sz;

void init(){
	for (int i=1;i<=n;i++)
		h[i] = num[i];
	sort(h+1,h+n+1);
	sz = unique(h+1,h+n+1) - h - 1; 
	tot = 0;
}

int hash(int x){return lower_bound(h+1,h+sz+1,x) - h;}

int Build(int l,int r){
	int root = tot++;
	data[root] = 0;	
	if (l < r){
		int mid = l+r>>1;		
		lson[root] = Build(l,mid);
		rson[root] = Build(mid+1,r);
	}
	return root;
}

int update(int root,int pos,int val){
	int newroot = tot++;
	int ret = newroot;
	data[newroot] = data[root] + val;
	int l = 1,r = sz;
	while (l<r){
		int mid = l+r>>1;
		if (pos <= mid){
			lson[newroot] = tot++;rson[newroot] = rson[root];	
			newroot = lson[newroot];root = lson[root];
			r = mid;
		}else {
			lson[newroot] = lson[root];rson[newroot] = tot++;
			newroot = rson[newroot];root = rson[root];
			l = mid+1;
		}
		data[newroot] = data[root] + val;
	}
	return ret;
}

int Query(int lt,int rt,int k){
	int lb = 1,rb = sz,mid;
	while (lb < rb){
		mid = lb+rb>>1;	
		if (data[lson[rt]] - data[lson[lt]] >= k){
			lt = lson[lt];rt = lson[rt];
			rb = mid;
		}else {
			k -= data[lson[rt]] - data[lson[lt]];
			lt = rson[lt];rt = rson[rt];
			lb = mid + 1;
		}
	}
	return lb;
}

int main(){
	std::ios::sync_with_stdio(false);cin.tie(0);
	int i,j;
	while (cin >> n >> m){
		for (i=1;i<=n;i++) cin >> num[i];
		init();
		T[0] = Build(1,sz);	
		for (i=1;i<=n;i++){
			int pos = hash(num[i]);
			T[i] = update(T[i-1],pos,1);	
		}
		while (m--){
			int l,r,k;	
			cin >> l >> r >> k;
			cout << h[Query(T[l-1],T[r],k)] << endl;
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值