1. 程式人生 > >poj 2104 主席樹板子題

poj 2104 主席樹板子題

講真這道題我感覺可以暴力

本篇部落格的意思是讓我們理解一下主席樹板子的具體實現細節

給予那些看懂了思路但是看不懂板子的人的一條小道

。。。其實就是主席樹亂講。。。。

表打我這個蒟蒻 >   <

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=100005;

struct node
{
	int L,R;
	int sum;
}tree[maxn*20];

struct Value
{
	int x;
	int id;
}value[maxn];

bool cmp(Value a,Value b)
{
	return a.x<b.x;
}

int root[maxn];
int rank[maxn];
int cnt;

void updata(int &rt,int num,int l,int r)
{ 
	tree[cnt++]=tree[rt];//copy 如果rt是根節點 那麼將上一個根節點的元素複製一份(main函式中的root‘i’=root‘i-1’) 在本根節點再做更新
	rt=cnt-1;
	/*
	類似於:
	tree[cnt]=tree[rt];cnt作為新節點 複製的內容是上一級線段樹的同一位置的內容 其實上面也是這個意思 只是我tm懶得刪 
	rt=cnt;
	cnt++;
	*/ 
	tree[rt].sum++;
	if(r==l) return;
	int mid=(l+r)>>1;
	if(num<=mid) updata(tree[rt].L,num,l,mid);
	else updata(tree[rt].R,num,mid+1,r);
} 

int query(int i,int j,int k,int l,int r)
{
	int mid=(l+r)>>1;
	int left_sum=tree[tree[j].L].sum-tree[tree[i].L].sum;//區間左邊元素個數
	if(l==r) return l;
	if(k<=left_sum) return query(tree[i].L,tree[j].L,k,l,mid);//當左邊元素個數多於k個 那第k小的就在左邊 
	else return query(tree[i].R,tree[j].R,k-left_sum,mid+1,r); 
}

int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&value[i].x);
		value[i].id=i;
	}
	sort(value+1,value+1+n,cmp);
	for(int i=1;i<=n;i++)
	{
		rank[value[i].id]=i;
	}
	cnt=1;
	root[0]=0;
	tree[0].L=tree[0].R=tree[0].sum=0;
	for(int i=1;i<=n;i++)
	{
		root[i]=root[i-1];
		updata(root[i],rank[i],1,n);
	}
	for(int i=1;i<=m;i++)
	{
		int x,y,k;
		scanf("%d%d%d",&x,&y,&k);
		int ans=value[query(root[x-1],root[y],k,1,n)].x;
		printf("%d\n",ans);
	}
}