块状数组+归并树学习 poj2104+hdu2665

今天在大白(挑战程序设计)上重新看了一遍分块数组相关的内容,虽然以前看过了,也做过相关的题目,但是总感觉只知道思想,自己不敢实现,今天把上面的例题照着敲了敲,也算加深了印象吧。

例题:POJ2104HDU2665

这两个是题都是求区间第K大,只不过HDU上数据强并且时间限制少了点。

以前以为平方分割求这种题还挺快的,没想到啊。。在POJ  11000+ms勉强水过,在HDU无情T掉。

不过归并树倒是有些出乎我意料的快,POJ  6000+ms,HDU 3500+ms

归并树之所以叫归并树是因为这一整棵树刚好是归并排序的完整再现。

今天除了温习了这两种数据结构,新收获是get了库函数merge的用法,以及!以后在这两个OJ上交题千万注意的一

点 ! 当你交C++  T了的时候不妨交一发G++试一试,极大可能会有惊喜,上面这两种算法我交C++都是TLE,很气。


PS:区间第K大一类的问题好像是主席树裸题,看人家400+ms轻松跑过的题而我要跑11000+ms,真的是欲哭无泪啊,改天膜拜一下主席树回来再战!

poj  的块状数组代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<stdio.h>
#include<math.h>
using namespace std;
const int MAXN=100010;
const int B=1000;
vector<int>bucket[MAXN];
int a[MAXN],tmp[MAXN];
void init(int n)
{
    for(int i=0;i<n;i++)
    {
        bucket[i/B].push_back(a[i]);
        tmp[i]=a[i];
    }
    sort(tmp,tmp+n);
    for(int i=0;i<n/B;i++)
        sort(bucket[i].begin(),bucket[i].end());
}
int check(int mid,int tl,int tr)
{
    int x=tmp[mid];
    int cnt=0;
    //区间两端多出的部分
    while(tl < tr && tl % B) if(a[tl++] <= x) cnt++;
    while(tl < tr && tr % B) if(a[--tr] <= x) cnt++;
    //对每一个桶进行计算
    while(tl < tr)
    {
        int b = tl / B;
        cnt += upper_bound(bucket[b].begin(), bucket[b].end(),x) - bucket[b].begin();
        tl += B;
    }
    return cnt;
}
int solve(int L,int R,int K,int n)
{
    int l=0,r=n-1,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(check(mid,L,R+1) >= K)
        r = mid-1;
        else
        l = mid+1;
    }
    //cout<<l<<" "<<r<<endl;
    return tmp[r+1];
}
int main()
{
    int n,m,l,r,k,T;
    //cin>>T;
    //while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%d",a+i);
        init(n);
        while(m--)
        {
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",solve(l-1,r-1,k,n));
        }
    }
}


HDU的归并树:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MAXN = 100010;
int a[MAXN];
vector<int>tree[MAXN<<2];
void build(int l,int r,int rt)
{
	if(l==r)
	{
		tree[rt].push_back(a[l]);
		return ;
	} 
	int mid=(l+r)>>1;
	build(lson);
	build(rson);
	tree[rt].resize(r-l+1);
	merge(tree[rt<<1].begin(),tree[rt<<1].end(),tree[rt<<1|1].begin(),tree[rt<<1|1].end(),tree[rt].begin());
}

int query(int L,int R,int x,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		return upper_bound(tree[rt].begin(),tree[rt].end(),x)-tree[rt].begin(); 
	}
	int mid=(l+r)>>1,sum=0;
	if(L<=mid)
	sum+=query(L,R,x,lson);
	if(R>mid)
	sum+=query(L,R,x,rson);
	return sum;
}
int tmp[MAXN];
int solve(int L,int R,int k,int n)
{
	int l=1,r=n,mid;
	while(l<=r)
	{
		mid=(l+r)>>1;
		if(query(L,R,tmp[mid],1,n,1) >= k)
		r=mid-1;
		else
		l=mid+1;
	}
	return tmp[r+1];
}
int main()
{
	int n,m,l,r,k;
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		for(int i=1;i<=n;i++)
		scanf("%d",a+i),tmp[i]=a[i];
		build(1,n,1);
		sort(tmp+1,tmp+n+1);
		while(m--)
		{
			scanf("%d%d%d",&l,&r,&k);
			printf("%d\n",solve(l,r,k,n));
		}
		for(int i=0;i<MAXN*4;i++)
		tree[i].clear();	
	}
} 



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值