HDU 4417 划分树+二分

题意:有n个数,m个询问(l,r,k),问在区间[l,r] 有多少个数小于等于k。

划分树——查找区间第k大的数。。。。

利用划分树的性质,二分查找在区间[l,r]小于等于k的个数。

如果在区间第 i 大的数tmp>k,则往下找,如果tmp<k,往上找。

#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<map>
#include<cmath>
#include<iostream>
#include <queue>
#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define INF 1e8
#define eps 1e-8
#define LL long long
#define N 100010
#define mod  1000000007 

int a[N],s[N],t[20][N],num[20][N],n,m;

void build(int c,int l,int r)
{
	if(l==r) return;
	int mid=(l+r)/2;
	int lm=mid-l+1,lp=l,rp=mid+1;
	for(int i=l;i<=r;i++)
		lm-=s[i]<s[mid];
	for(int i=l;i<=r;i++)
	{
		if(i==l)
			num[c][i]=0;
		else num[c][i]=num[c][i-1];
		if(t[c][i]==s[mid])
		{
			if(lm)
			{
				lm--;
				num[c][i]++;
				t[c+1][lp++]=t[c][i];
			}
			else t[c+1][rp++]=t[c][i];
		}
		else if(t[c][i]<s[mid])
		{
			num[c][i]++;
			t[c+1][lp++]=t[c][i];
		}
		else t[c+1][rp++]=t[c][i];
	}
	build(c+1,l,mid);
	build(c+1,mid+1,r);
}

int query(int c,int l,int r,int ql,int qr,int k)
{
	if(l==r)
		return t[c][l];
	int s,ss,mid=(l+r)/2;
	if(ql==l)
		s=0,ss=num[c][qr];
	else s=num[c][ql-1],ss=num[c][qr]-num[c][ql-1];
	if(k<=ss)
		return query(c+1,l,mid,l+s,s+l+ss-1,k);
	else return query(c+1,mid+1,r,mid+1+ql-l-s,mid+1+qr-l-s-ss,k-ss);
}

int main()
{
	int T,ca=1;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			s[i]=t[0][i]=a[i];
		}
		sort(s+1,s+n+1);
		build(0,1,n);
		printf("Case %d:\n",ca++);
		while(m--)
		{
			int l,r,k;
			scanf("%d%d%d",&l,&r,&k);
			l++;r++;
			if(query(0,1,n,l,r,r-l+1)<=k)
				printf("%d\n",r-l+1);
			else if(query(0,1,n,l,r,1)>k)
				puts("0");
			else
			{
				int ll=0,rr=r-l+1,mid;
				while(ll<=rr)
				{
					mid=(ll+rr)>>1;
					int tmp=query(0,1,n,l,r,mid);//如果在区间[l,r]第mid大的数大于k,rr=mid-1
					if(tmp>k)
						rr=mid-1;
					else ll=mid+1;//否则ll=mid+1
				}
				printf("%d\n",ll-1);
			}
		}
	}
	return 0;
}
/*
1
10 10
0 5 2 7 5 4 3 8 7 7
2 8 6
3 5 0
1 3 1
1 9 4
0 1 0
3 5 5
5 5 1
4 6 3
1 5 7
5 7 3
*/

HDU 4417 划分树+二分,布布扣,bubuko.com

时间: 2024-10-11 22:01:53

HDU 4417 划分树+二分的相关文章

HDU 4417 (划分树+区间小于k统计)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的. 解题思路: 首先这题线段树可以解.方法是维护一个区间最大值max,一个区间点个数s,如果k>max,则ans=s+Q(rson),否则ans=Q(lson). 然后也可以用求区间第K大的划分树来解决,在对原来求第K大的基础上改改就行,方法如下: Build方法同第K大. 对于Query: ①左区

HDU-4417-Super Mario(划分树+二分)

Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss's castle as a l

sdut 2610:Boring Counting(第四届山东省省赛原题,划分树 + 二分)

Boring Counting Time Limit: 3000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence. Now you task is to answer a list of queries, for each quer

【划分树+二分】HDU 4417 Super Mario

第一次 耍划分树.. . 模板是找第k小的 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <queue> #include &l

hdu4417 划分树+二分

1 //Accepted 14796 KB 453 ms 2 //划分树 3 //把查询的次数m打成n,也是醉了一晚上!!! 4 //二分l--r区间第k大的数和h比较 5 #include <cstdio> 6 #include <cstring> 7 #include <iostream> 8 #include <queue> 9 #include <cmath> 10 #include <algorithm> 11 using

hdu 2665 划分树

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <stack> #include <set> #include <map> #include <vector> using namespace st

hdu 3473 划分树 ***

题目大意:有一个数列 x1..xn,要求一个数x使得 sigma(abs(xi-x))值最小,很明显,对数列进行排序后最中间的那个数就是x,可用划分树求得,那么如何求和呢,经过计算可知,既然 x 是最中间的那个数,那么最后的和 即为 x左边 xmid-x1+xmid-x2.. +  x(mid+1) - xmid + x(mid+2)-xmid..  整理得 xmid*(lefnum-rignum)+rigsum-lefsum lefnum为划分过程进入左子树的个数,lefsum为进入左子树的数

hdu 6070 线段树+二分

HDU - 6070 题意:提交了n次题目,每个题目都是最后一次提交的时候AC的,现在求一个区间,这个区间的AC率是最低的(只考虑这个区间内的题目,同样区间内最后交的一遍是AC的),求最低的AC率 思路:AC率=提交次数/题目数目,即区间长度/题目种类,siz[l,r]/(r-l+1)=p(siz[l,r]表示l r区间内的不同题目的个数,p表示AC率), 把式子做一下调整,siz[l,r]+p*l=p(r+1),二分p(0-1)用线段树维护siz[l,r]+l*p ,然后枚举r,每次更新,因为

13年山东省赛 Boring Counting(离线树状数组or主席树+二分or划分树+二分)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 2224: Boring Counting Time Limit: 3 Sec  Memory Limit: 128 MB Description In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence.