主席树模板 + 题解(无修改)

POJ2104、POJ2761:

题意:区间第K小。

两道题几乎是一样的。

AC代码:

/*---------------------------------
File name: poj2104.cpp
Author: Snpilola
Creation date: 2019-08-09 14:17
---------------------------------*/
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define mkp make_pair
#define PLL pair<LL, LL>
#define PII pair<int, int>
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int ls[maxn << 5], rs[maxn << 5], cnt[maxn << 5], root[maxn << 5], tot;
int num[maxn], hash[maxn];

void build(int l, int r, int &rt){
	rt = tot++;
	cnt[rt] = 0;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(l, mid, ls[rt]);
	build(mid + 1, r, rs[rt]);
}

void update(int last, int p, int l, int r, int &rt){
	rt = tot++;
	ls[rt] = ls[last], rs[rt] = rs[last];
	cnt[rt] = cnt[last] + 1;	
	if(l == r) return;
	int mid = (l + r) >> 1;
	if(p <= mid) update(ls[last], p, l, mid, ls[rt]);
	else update(rs[last], p, mid + 1, r, rs[rt]);
}

int query(int ss, int tt, int l, int r, int k){
	if(l == r) return l;
	int mid = (l + r) >> 1, sum = cnt[ls[tt]] - cnt[ls[ss]];
	if(k <= sum) return query(ls[ss], ls[tt], l, mid, k);
	else return query(rs[ss], rs[tt], mid + 1, r, k - sum);
}

int main(){
	int n, m, l, r, k;
	while(~ scanf("%d %d", &n, &m)){
		for(int i = 1; i <= n; ++i){
			scanf(" %d", &num[i]);
			hash[i] = num[i];
		}
		sort(hash + 1, hash + 1 + n);
		int size = unique(hash + 1, hash + 1 + n) - hash - 1;//unique前先sort
		//unique函数返回最后一个不重复元素,实际数组长度无变化
		for(int i = 1; i <= n; ++i){
			num[i] = lower_bound(hash + 1, hash + size + 1, num[i]) - hash;
		}
		tot = 0;
		build(1, size, root[0]);//建空树
		for(int i = 0; i < 4 * size; i++) printf("%d %d %d\n", root[i], ls[i], rs[i]);
		//printf("----------\n");
		for(int i = 1; i <= n; ++i){
			update(root[i - 1], num[i], 1, size, root[i]);//填树
			//printf("%d %d %d\n", root[i], ls[root[i]], rs[root[i]]);
		}
		while(m--){
			scanf("%d %d %d", &l, &r, &k);//区间[l, r]的第k小||大
			printf("%d\n", hash[query(root[l - 1], root[r], 1, size, k)]);
		}
	}
	return 0;
}

 

/*---------------------------------
File name: poj2761.cpp
Author: Snpilola
Creation date: 2019-08-08 10:32
---------------------------------*/
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define mkp make_pair
#define PLL pair<LL, LL>
#define PII pair<int, int>
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int a[maxn];
int Hash[maxn];
int root[maxn << 5], ls[maxn << 5], rs[maxn << 5], cnt[maxn << 5];
int tot;

void build(int l, int r, int &rt){
	rt = tot++;
	cnt[rt] = 0;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(l, mid, ls[rt]);
	build(mid + 1, r, rs[rt]);
}

void update(int last, int p, int l, int r, int &rt){
	rt = tot++;
	ls[rt] = ls[last];
	rs[rt] = rs[last];
	cnt[rt] = cnt[last] + 1;
	if(l == r) return ;
	int mid = (l + r) >> 1;
	if(p <= mid) update(ls[rt], p, l, mid, ls[rt]);
	else update(rs[rt], p, mid + 1, r, rs[rt]);
}

int query(int ss, int tt, int l, int r, int k){
	if(l == r) return r;
	int mid = (l + r) >> 1;
	int sum = cnt[ls[tt]] - cnt[ls[ss]];
	if(k <= sum) query(ls[ss], ls[tt], l, mid, k);
	else query(rs[ss], rs[tt], mid + 1, r, k - sum);
}

int main(){
	int t; scanf("%d", &t);
	while(t--){
		int n, m; scanf("%d %d", &n, &m);
		for(int i = 1; i <= n; ++i){
			scanf(" %d", &a[i]);
			Hash[i] = a[i];
		}
		sort(Hash + 1, Hash + 1 + n);
		int Size = unique(Hash + 1, Hash + 1 + n) - Hash - 1;
		for(int i = 1; i <= n; i++){
			a[i] = lower_bound(Hash + 1, Hash + 1 + Size, a[i]) - Hash;
		}
		tot = 0;
		build(1, Size, root[0]);
		for(int i = 1; i <= n; i++){
			update(root[i - 1], a[i], 1, Size, root[i]);
		}
		while(m--){
			int i, j, k;
			scanf("%d %d %d", &i, &j, &k);
			printf("%d\n", Hash[query(root[i - 1], root[j], 1, Size, k)]);
		}
	}
	return 0;
}

 

HDU4417:

Input:

1
10 10
0 5 2 7 5 4 3 8 7 7 
2 8 6
3 5 0
1 3 1
1 9 4
0 1 0
3 5 5
5 5 1
4 6 3
1 5 7
5 7 3

Output:

Case 1:
4
0
0
3
1
2
0
1
5
1

题意:求给定区间【L, R】中不大于H的数的个数。

思路:只需要改一下query的部分就可以了。

AC代码:

/*---------------------------------
File name: hdu4417.cpp
Author: Snpilola
Creation date: 2019-08-08 11:07
---------------------------------*/
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define mkp make_pair
#define PLL pair<LL, LL>
#define PII pair<int, int>
#define Pque priority_queue 
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

int a[maxn];
int Hash[maxn];
int root[maxn << 5], ls[maxn << 5], rs[maxn << 5], cnt[maxn << 5];
int tot;

void build(int l, int r, int &rt){
	rt = tot++;
	cnt[rt] = 0;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(l, mid, ls[rt]);
	build(mid + 1, r, rs[rt]);
}

void update(int last, int p, int l, int r, int &rt){
	rt = tot++;
	ls[rt] = ls[last];
	rs[rt] = rs[last];
	cnt[rt] = cnt[last] + 1;
	if(l == r){
		//printf("cnt = %d, l = %d, r = %d\n", cnt[rt], l, r);
		return ;
	}
	int mid = (l + r) >> 1;
	if(p <= mid) update(ls[last], p, l, mid, ls[rt]);
	else update(rs[last], p, mid + 1, r, rs[rt]);
}

int query(int ss, int tt, int l, int r,int x){
	if(l == r) return x < l ? 0 : (cnt[tt] - cnt[ss]);
	int mid = (l + r) >> 1;
	if(x <= mid) return query(ls[ss], ls[tt], l, mid, x);
	else return cnt[ls[tt]] - cnt[ls[ss]] + query(rs[ss], rs[tt], mid + 1, r, x);
}

int main(){
	int t; scanf("%d", &t);
	int cast = 0;
	while(t--){
		int n, m; scanf("%d %d", &n, &m);
		for(int i = 1; i <= n; i++){
			scanf(" %d", &a[i]);
			Hash[i] = a[i];
		}
		sort(Hash + 1, Hash + 1 + n);
		int Size = unique(Hash + 1, Hash + 1 + n) - Hash - 1;
		for(int i = 1; i <= n; i++){
			a[i] = lower_bound(Hash + 1, Hash + 1 + Size, a[i]) - Hash;
		}
		//for(int i = 1; i <= n; i++) printf("%d ", a[i]); cout << endl;
		tot = 0;
		build(1, Size, root[0]);
		for(int i = 1; i <= n; i++){
			update(root[i - 1], a[i], 1, Size, root[i]);
		}
		printf("Case %d:\n", ++cast);
		while(m--){
			int i, j, k;
			scanf("%d %d %d", &i, &j, &k);
			k = upper_bound(Hash + 1, Hash + 1 + Size, k) - Hash - 1;
			printf("%d\n", query(root[i], root[j + 1], 1, Size, k));
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值