线段树静态主席树查询动态开点

线段树静态主席树查询动态开点

很久很久以前,第k小问题突然出现……
有这样一棵线段树,它领悟了动态开点,经历了持久化,装备上了权值,最后得到了西主席(其实是黄嘉泰大佬,由于首字母啊…所以)的赐名,成功升级为了全新版本的线段树——主席树。
由于主席树很吃空间(一般是20*maxn或者maxn<<5),所以如果可以的话不要建立最开始的线段树,在更新的时候建链维护就行
贴一段学长的话
关于空间问题,我们分析一下:由于我们是动态开点的,所以一棵线段树只会出现2n - 1个结点。然后,有n次修改,每次至多增加[ l o g 2 n {log_2{n}} log2n] + 1个结点。因此,最坏情况下n次修改后的结点总数会达到2n - 1 + n ([ l o g 2 n {log_2{n}} log2n] + 1)。 此题的 n <= 105 {105} 105,单次修改至多增加[ l o g 2 105 {log_2{105}} log2105] + 1 = 18 个结点,故n次修改后的结点总数为 2 * 10 - 1 + 18 * 1 0 5 {10^5} 105,忽略掉-1,大概就是20 * 1 0 5 {10^5} 105
最后给一个忠告:千万不要吝啬空间(大多数题目中空间限制都较为宽松,因此一般不用担心空间超限的问题)!保守一点,直接上个 2 5 {2^5} 25 * 1 0 5 {10^5} 105接近原空间的两倍(即 n << 5)。
一般不用担心,当然也只是一般而已。。。

板子题,题目大意:给一串数,求第a个到第b个数之间(含a,b)的第k值(注意题描述的有问题不是第k大)

前置技能:离散化

忘了的话看这个:链接

Kth number

HDU版:HDU - 2665

Give you a sequence and ask you the kth big number of a inteval.
Input
The first line is the number of the test cases.
For each test case, the first line contain two integer n and m (n, m <= 100000), indicates the number of integers in the sequence and the number of the quaere.
The second line contains n integers, describe the sequence.
Each of following m lines contains three integers s, t, k.
[s, t] indicates the interval and k indicates the kth big number in interval [s, t]
Output
For each test case, output m lines. Each line contains the kth big number.
Sample Input
1
10 1
1 4 2 3 5 6 7 8 9 0
1 3 2
Sample Output
2

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int c,n,m,cnt,un;
int w[maxn],line[maxn],root[maxn]; 
struct tree{
	int sum,lson,rson;
}seg[maxn*20];
int update(int n,int pre,int l,int r){//更新时间版本主席树(建立新链) 
	int cur=++cnt;
	seg[cur]=seg[pre];
	seg[cur].sum=seg[pre].sum+1;
	if(l!=r){
		int mid=(l+r)/2;
		if(n<=mid)
    	seg[cur].lson=update(n,seg[pre].lson,l,mid);
    	else
		seg[cur].rson=update(n,seg[pre].rson,mid+1,r);
	}
	return cur;
}
int query(int u,int v,int k,int l,int r){//查询
	if(l==r)
	return l;
	int mid=(l+r)/2;
	if((seg[seg[v].lson].sum-seg[seg[u].lson].sum)>=k)
	return query(seg[u].lson,seg[v].lson,k,l,mid);
	else
	return query(seg[u].rson,seg[v].rson,k-(seg[seg[v].lson].sum-seg[seg[u].lson].sum),mid+1,r);
}
int main(){
	scanf("%d",&c);
	while(c--){
		scanf("%d%d",&n,&m);
		cnt=un=0;
        seg[0].lson=seg[0].rson=seg[0].sum=w[0]=line[0]=root[0]=0; 
		for(int i=1;i<=n;i++){
			scanf("%d",&w[i]);
			line[i]=w[i];
		}
		sort(w+1,w+1+n);//sort,unique,lower_bound都是离散化过程 
		un=unique(w+1,w+1+n)-w-1;
		for(int i=1;i<=n;i++){
			line[i]=lower_bound(w+1,w+1+un,line[i])-w;
			root[i]=update(line[i],root[i-1],1,un);//记录每一个时间版本的主席树根节点 
		}
		while(m--){
			int a,b,k,ans=0;
			scanf("%d%d%d",&a,&b,&k);
			ans=query(root[a-1],root[b],k,1,un);//在两个时间版本的主席树上进行查询 
			printf("%d\n",w[ans]);
		}
	}
    return 0;
}

POJ版:POJ - 2104

You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array segment.
That is, given an array a[1…n] of different integer numbers, your program must answer a series of questions Q(i, j, k) in the form: “What would be the k-th number in a[i…j] segment, if this segment was sorted?”
For example, consider the array a = (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2…5] is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number is 5, and therefore the answer to the question is 5.
Input
The first line of the input file contains n — the size of the array, and m — the number of questions to answer (1 <= n <= 100 000, 1 <= m <= 5 000).
The second line contains n different integer numbers not exceeding 109 by their absolute values — the array for which the answers should be given.
The following m lines contain question descriptions, each description consists of three numbers: i, j, and k (1 <= i <= j <= n, 1 <= k <= j - i + 1) and represents the question Q(i, j, k).
Output
For each question output the answer to it — the k-th number in sorted a[i…j] segment.
Sample Input
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
Sample Output
5
6
3
Hint
This problem has huge input,so please use c-style input(scanf,printf),or you may got time limit exceed.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int c,n,m,cnt,un;
int w[maxn],line[maxn],root[maxn]; 
struct tree
{
	int sum,lson,rson;
}seg[maxn*20];
int update(int n,int pre,int l,int r)
{
	int cur=++cnt;
	seg[cur]=seg[pre];
	seg[cur].sum=seg[pre].sum+1;
	if(l!=r)
	{
		int mid=(l+r)/2;
		if(n<=mid)
    	seg[cur].lson=update(n,seg[pre].lson,l,mid);
    	else
		seg[cur].rson=update(n,seg[pre].rson,mid+1,r);
	}
	return cur;
}
int query(int u,int v,int k,int l,int r)
{
	if(l==r)
	return l;
	int mid=(l+r)/2;
	if((seg[seg[v].lson].sum-seg[seg[u].lson].sum)>=k)
	return query(seg[u].lson,seg[v].lson,k,l,mid);
	else
	return query(seg[u].rson,seg[v].rson,k-(seg[seg[v].lson].sum-seg[seg[u].lson].sum),mid+1,r);
}
int main()
{
//	scanf("%d",&c);
//	while(c--)
//	{
		scanf("%d%d",&n,&m);
		cnt=un=0;
        seg[0].lson=seg[0].rson=seg[0].sum=w[0]=line[0]=root[0]=0; 
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&w[i]);
			line[i]=w[i];
		}
		sort(w+1,w+1+n);
		un=unique(w+1,w+1+n)-w-1;
		for(int i=1;i<=n;i++)
		{
			line[i]=lower_bound(w+1,w+1+un,line[i])-w;
			root[i]=update(line[i],root[i-1],1,un);
		}
		while(m--)
		{
			int a,b,k,ans=0;
			scanf("%d%d%d",&a,&b,&k);
			ans=query(root[a-1],root[b],k,1,un);
			printf("%d\n",w[ans]);
		}
//	}
    return 0;
}

2021.7.27

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值