POJ 2761 静态区间K大

。。可持久化线段树模板题

具体讲解看CLJ神犇的论文,总之函数式编程的关键就是不要赋值,每次都新建节点就好了。


【代码】

/************************
    ID:Ciocio
	LANG:C++
	DATE:2014-1-22
	TASK:Feed the dogs
************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>

using namespace std;

#define MAXP 4000000
#define MAXN 100005
#define m_p make_pair
#define INF 999999999

struct Tree{
	Tree* lc;
	int sz;
	Tree* rc;
};
Tree Pool[MAXP];
Tree* New=Pool;
Tree* null;
Tree* P[MAXN];
int N,M;
typedef pair<int,int> pii;
pii V[MAXN];
int initkey[MAXN],mat[MAXN];

void _read(int &x)
{
	char tt=getchar();
	while(tt<'0'||'9'<tt) tt=getchar();
	for(x=0;'0'<=tt&&tt<='9';x=(x<<1)+(x<<3)+tt-'0',tt=getchar());
}

char t[100];
void _write(int x,int j=1)
{
	if(x==0) putchar('0');
	for(;x;x/=10,j++) t[j]=x%10+'0';
	for(j--;j;j--) putchar(t[j]);
	putchar('\n');
}

Tree* Get(Tree* lc,int sz,Tree* rc)
{
	New->lc=lc;
	New->sz=sz;
	New->rc=rc;
	return New++;
}

Tree* Insert(Tree* T,int loc,int Left,int Right)
{
	if(Left==Right) return Get(0,T->sz+1,0);
	int Mid=(Left+Right)>>1;
	Tree* tmp;
	if(loc<=Mid)
	{
		tmp=Insert(T->lc,loc,Left,Mid);
		return Get(tmp,tmp->sz+T->rc->sz,T->rc);
	}
	if(loc>=Mid+1)
	{
	    tmp=Insert(T->rc,loc,Mid+1,Right);
	    return Get(T->lc,T->lc->sz+tmp->sz,tmp);
	}
}

void _renumbered()
{
	sort(V+1,V+N+1);
    int tmp=0;
    V[0]=m_p(-INF,0);
    for(int i=1;i<=N;i++)
    {
        if(V[i].first!=V[i-1].first) tmp++;
        initkey[V[i].second]=tmp;
        mat[tmp]=V[i].first;
    }
}

void _init()
{
	_read(N);_read(M);
	int x;
	null=Get(0,0,0);
	null->lc=null;
	null->rc=null;
	P[0]=null;
	for(int i=1;i<=N;i++) 
	{
		_read(x);
		V[i]=m_p(x,i);
    }
    _renumbered();
    for(int i=1;i<=N;i++) P[i]=Insert(P[i-1],initkey[i],1,N);
    
}

int Search(Tree* A,Tree* B,int k,int Left,int Right)
{
	int Mid=(Left+Right)>>1;
	if(Left==Right) return Left;
	if(k<=B->lc->sz-A->lc->sz) 
		return Search(A->lc,B->lc,k,Left,Mid);
	else 
	{
		k-=B->lc->sz-A->lc->sz;
		return Search(A->rc,B->rc,k,Mid+1,Right);
	}
}

void _solve()
{
	int a,b,k;
	for(int i=1;i<=M;i++)
	{
		_read(a);_read(b);_read(k);
		_write(mat[Search(P[a-1],P[b],k,1,N)]);
	}
}

int main()
{
	_init();
	_solve();
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值