POJ 2761 据说可以练习线段树主席树划分树splay和treap的一道题。。我用BIT+二分+离散化搞的。。

7 篇文章 0 订阅

查询区间第 K 小的数,这个二分+树状数组足够了啊。

虽然我是想练练treap 的,但是看到能写 BIT 就停不下来啊。。。

离散化好恶心。。。用map T 到死。还有大于1000W 的数数组开不下,只能 hash。

找了两三个素数才过的去。

hash的时候素数不是越大越好啊。。?

中途开了好多个struct来保存信息。。。

#include <stdio.h>
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <cmath>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fstream>
using namespace std;

#define READ freopen("acm.in","r",stdin)
#define ll long long
#define PII pair<int,int>
#define PDI pair<double,int>
#define PDD pair<double,double>
#define MPI map<int,int>::iterator 
#define fst first
#define sec second
#define MS(x,d) memset(x,d,sizeof(x))
#define INF 0x3f3f3f3f
#define ALL(x) x.begin(),x.end()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MAX 200000
#define ROOT 0,n-1,1
#define PB push_back
#define FOR(a,b,c) for(int a=b;a<c;a++)
#define MOD 486377
struct answer
{
    int i,ans;
    bool operator < (const answer &o) const
    {
        return i<o.i;
    }
}Ans[MAX];
struct q
{
    int l,r,k,i;
    bool operator < (const q &o) const
    {
        if(r==o.r)
            return l<o.l;
        return r<o.r;
    }
}Q[MAX];
struct hashNode
{
    int num;
    int i;
};
int data[2000000];
int n,m;
int num[MAX];
void add(int i,int x)
{
    while(i<=n)
    {
        data[i]+=x;
        i+=i&(-i);
    }
}
int sum(int i)
{
    int res=0;
    while(i>0)
    {
        res+=data[i];
        i-=i&(-i);
    }
    return res;
}

int query(int k)
{
    int lb=0,ub=n;
    while(ub-lb>1)
    {
        int mid=(lb+ub)>>1;
        if(sum(mid)>=k)
            ub=mid;
        else
            lb=mid;
    }
    return ub;
}
vector<int> uni;
vector<hashNode> mp[1000000];
void hash(int n,int i)
{
    mp[n%MOD].PB((hashNode){n,i});
}
int getHash(int n)
{
    for(int i=0;i<mp[n%MOD].size();i++)
        if(n==mp[n%MOD][i].num)
            return mp[n%MOD][i].i;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<1000000;i++)
            mp[i].clear();
        uni.clear();
        MS(data,0);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            uni.PB(num[i]);
        }
        sort(ALL(uni));
        uni.erase(unique(ALL(uni)),uni.end());
        for(int i=0;i<uni.size();i++)
            hash(uni[i],i+1);
        for(int i=1;i<=m;i++)
        {
            int l,r,k,in;
            scanf("%d%d%d",&l,&r,&k);
            Q[i]=(q){l,r,k,i};
        }
        sort(Q+1,Q+1+m);
        int L=1,R=1,nq=1;
        while(nq<=m)
        {
            while(R<=Q[nq].r)
            {
                add(getHash(num[R]),1);
                R++;
            }
            while(L<Q[nq].l)
            {
                add(getHash(num[L]),-1);
                L++;
            }
            Ans[nq]=(answer){Q[nq].i,uni[query(Q[nq].k)-1]};
            nq++;
        }
        sort(Ans+1,Ans+1+m);
        for(int i=1;i<=m;i++)
            printf("%d\n",Ans[i].ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值