My归并树,划分树模板。

POJ 2104 寻找区间第K数

划分树,时间复杂度O(MlogN),归并树,时间复杂度O(Mlog^3N)。

归并树

#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")

using namespace std;

const int MAX = 100010;
class Merger_tree{
public :
	class Tnode{
	public :
	    int l,r;
	    int len() { return r - l;}
	    int mid() { return MID(l,r);}
	    bool in(int ll,int rr) { return l >= ll && r <= rr; }
	    void lr(int ll,int rr){ l = ll; r = rr;}
	};
 	Tnode node[MAX<<2];
 	int seg[20][MAX],a[MAX],n;
	void init()
	{
		memset(seg,0,sizeof(seg));
		memset(node,0,sizeof(node));
	}
	void build(int s,int t){ n = t; Merger_build(1,s,t,1); }
	int find(int x,int y,int k) { return find_rank(n,x,y,k); };
	void Merger_build(int t,int l,int r,int deep)
	{
		node[t].lr(l, r);
		if( node[t].len() == 0 )
		{
			seg[deep][l] = a[l];
			return ;
		}
		int mid = MID(l, r);
		Merger_build(L(t), l, mid, deep+1);
		Merger_build(R(t), mid+1, r, deep+1);
		int k = l,i = l,j = mid+1;
		while( i <= mid && j <= r )
			if( seg[deep+1][i] < seg[deep+1][j] )
				seg[deep][k++] = seg[deep+1][i++];
			else
				seg[deep][k++] = seg[deep+1][j++];
		while( i <= mid )
			seg[deep][k++] = seg[deep+1][i++];
		
		while( j <= r )
			seg[deep][k++] = seg[deep+1][j++];
			
	}
	int find_k(int t,int l,int r,int deep,int val)
	{
		if( node[t].in(l,r) )
		{
			int ll = node[t].l, rr = node[t].r;
			while( ll < rr )
			{
				int mid = MID(ll, rr);
				if( seg[deep][mid] < val )
					ll = mid + 1;
				else
					rr = mid;
			}
			if( seg[deep][ll] <= val )
				return ll - node[t].l + 1;
			else
				return ll - node[t].l;
		}
		if( node[t].len() == 0 ) return 0;
		int ans = 0;
		int mid = node[t].mid();
		if( l <= mid ) ans += find_k(L(t), l, r, deep+1, val);
		if( r >= mid ) ans += find_k(R(t), l, r, deep+1, val);
		return ans;
	}		
	int find_rank(int n,int x,int y,int k)
	{
		int l = 1,r = n;
		while( l < r )
		{
			int mid = MID(l, r);
			if( find_k(1, x, y, 1, seg[1][mid]) < k )
				l = mid + 1;
			else
				r = mid;
		}
		return seg[1][l];
	}
};

Merger_tree t; 
int main()
{
	int n,m,x,y,k;
	while( ~scanf("%d%d",&n,&m) )
	{
		t.init();
		for(int i=1; i<=n; i++)
			scanf("%d",&t.a[i]);
		
		t.build(1,n);
		while( m-- )
		{
			scanf("%d%d%d",&x,&y,&k);
			int ans = t.find(x,y,k);
			printf("%d\n",ans);
		}
	}

return 0;
}


划分树

#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define BUG puts("here!!!")

using namespace std;

const int MAX = 100010;
class Parti_tree{
public : 
	class Tnode{
	public :
	    int l,r;
	    int len() { return r - l;}
	    int mid() { return MID(l,r);}
	    bool in(int ll,int rr) { return l >= ll && r <= rr; }
	    void lr(int ll,int rr){ l = ll; r = rr;}
	};
	Tnode node[MAX<<2];
	int Left[20][MAX], seg[20][MAX], sa[MAX];
	void init()
	{
		memset(Left,0,sizeof(Left));
		memset(node,0,sizeof(node));
	}
	void build(int s,int t){ sort(sa+1,sa+t+1); Parti_build(1,s,t,1); }
    int find(int s,int t,int k){ return find_rank(1,s,t,1,k); }
	void Parti_build(int t,int l,int r,int d)
	{
		node[t].lr(l, r);
		if( node[t].len() == 0 ) return ;
		int mid = MID(l, r), lsame = mid - l + 1;
		for(int i=l; i<=r; i++)
			if( seg[d][i] < sa[mid] )
				lsame--;
		int lpos = l,rpos = mid+1,same = 0;
		for(int i=l; i<=r; i++)
		{
			if( i == l )
				Left[d][i] = 0;
			else
				Left[d][i] = Left[d][i-1];
			if( seg[d][i] < sa[mid] )
			{
				Left[d][i]++;
				seg[d+1][lpos++] = seg[d][i];
			}
			if( seg[d][i] > sa[mid] )
				seg[d+1][rpos++] = seg[d][i];
			if( seg[d][i] == sa[mid] )
				if( same < lsame )	
				{
					same++;
					Left[d][i]++;
					seg[d+1][lpos++] = seg[d][i];
				}
				else
					seg[d+1][rpos++] = seg[d][i];
		}
		Parti_build(L(t), l, mid, d+1);
		Parti_build(R(t), mid+1, r, d+1);		
	}
	int find_rank(int t,int l,int r,int d,int val)
	{
		if( node[t].len() == 0 )
			return seg[d][l];
		int s,ss;
		if( l == node[t].l )
		{
			s = Left[d][r];
			ss = 0;
		}
		else
		{
			s = Left[d][r] - Left[d][l-1];
			ss = Left[d][l-1];
		}
		if( s >= val )
			return find_rank(L(t), node[t].l+ss, node[t].l+ss+s-1, d+1, val);
		else
		{
			int mid = node[t].mid();
			int bb = l - node[t].l - ss;
			int b = r - l + 1 - s;
			return find_rank(R(t), mid+bb+1, mid+bb+b,d+1,val-s);
		}
	}
};

Parti_tree t;
int main()
{
	int n,m,x,y,k;
	
	while( ~scanf("%d%d",&n,&m) )
	{
		t.init();
		for(int i=1; i<=n; i++)
		{
			scanf("%d",&t.sa[i]);
			t.seg[1][i] = t.sa[i];
		}
		t.build(1,n);
		while( m-- )
		{
			scanf("%d%d%d",&x,&y,&k);
			int ans = t.find(x, y, k);
			printf("%d\n",ans);
		}
	}

return 0;
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值