pku2761區間第k大數-二分+樹狀數組

 

http://poj.org/problem?id=2761

 

題意:給定一個數組,求一些區間的第k大數,數據比2104大10倍,開始沒怎麼看題,直接貼代碼tle了。。。這題有一個很重要的限制,那就是不存在包含關係的區間。。。

 

 

分析:那個限制條件是關鍵。。。在那個限制條件下,我們能很自然的想到對查詢排序,從從前往後掃,逐漸加點,刪點。。。。剩下的工作就和xmu那題一樣了。。。。

注意用樹狀數組需要先離散化。。。

 

 

代碼:

 

#include<algorithm>
#include<iostream>
#include<map>
using namespace std;

const int N=100010;
int sum[N], ans[N], c[N], n, m;//c存離散化後某個值對應的真值
struct lisan
{
	int i, ii, v; //ii爲原來數組的序號,i爲離散化後的值
}b[N];
struct node
{
	int l, r, k, i;
} a[N];
int cmp2(const lisan &a, const lisan &b)
{
	return a.ii<b.ii;
}
int cmp1(const lisan &a, const lisan &b)
{
	return a.v<b.v;
}
int cmp(const node &a, const node &b)
{
	return a.l < b.l;
}

void update(int i, int v)
{
	for(; i<=n; i+=i&(-i))
		sum[i] += v;
}
int query(int i)
{
	int tmp=0;
	for(; i>0; i-=i&(-i))
		tmp += sum[i];
	return tmp;
}

int bs(int k)
{
	int l=1,r=n, mid, tmp;
	while(l<=r)
	{
		mid = (l+r)>>1;
		tmp = query(mid);
		if(tmp>=k)
			r = mid-1;
		else
			l = mid+1;
	}
	return c[l];
}

int main()
{
	int i, j, ll, rr;
	while(scanf("%d%d", &n, &m)!=EOF)
	{
		for(i=1; i<=n; i++)
		{
			scanf("%d", &b[i].v);
			b[i].ii = i;
		}
		sort(b+1, b+n+1, cmp1);
		b[1].i = 1;
		c[1] = b[1].v;
		for(i=1, j=1; i<=n; i++)
		{
			if(b[i].v!=b[i-1].v)
				b[i].i = ++j;
			else
				b[i].i = j;
			c[j] = b[i].v;
		}
		sort(b+1, b+n+1, cmp2);
		for(i=1; i<=n; i++)
			sum[i] = 0;
		for(i=0; i<m; i++)
		{
			scanf("%d%d%d",&a[i].l, &a[i].r, &a[i].k);
			a[i].i = i;
		}
		sort(a, a+m, cmp);

		ll = rr = 1;
		for(i=0; i<m; i++)
		{
			while(rr<=a[i].r)
			{
				update(b[rr].i, 1);
				rr++;
			}
			
			while(ll<a[i].l)
			{
				update(b[ll].i, -1);
				ll++;
			}
			ans[a[i].i] = bs(a[i].k);	
		}
		for(i=0; i<m; i++)
			printf("%d\n", ans[i]);
	}
	return 0;
}


 

發佈了68 篇原創文章 · 獲贊 23 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章