【2012河南省队互测】【COGS930】找第k小的数

题目描述

看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,…,AN,

现在有M个询问,每个询问都是Ai…Aj中第k小的数等于多少。

输入格式

第一行两个正整数N,M。

第二行N个数,表示序列A1,A2,…,AN。

紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示

询问Ai…Aj中第k小的数等于多少。

输出格式

共输出M行,第i行输出第i个询问的答案。

样例输入1:

4 3

4 1 2 3

1 3 1

2 4 3

1 4 4

样例输出1:

1

3

4

样例输入2:

5 5

4 2 9 9 10

1 3 1

2 4 3

1 4 4

3 5 2

2 5 2

样例输出2:

2

9

9

9

9

注释:

询问区间的第k小值并非严格第k小,例如样例2中第4个询问,询问3到5中第2小的数,

答案输出9,并不是严格第2小的10。

数据范围:

在50%的数据中,1<=N<=10000,1<=M<=10000,A[i]<=100000;

在100%的数据中,1<=N<=100000,1<=M<=100000,A[i]<=1000000;

静态区间K大。我很开心的写了线段树的整体二分最后就被卡常数了魂淡

最后改树状数组才能A。

(为了刷榜读入优化)

//AC code by CreationAugust
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 110000
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
#define MAXINT 0x7fffffff
using namespace std;
int n,m;
int maxn;
int a[MAXN<<2];
int tree[MAXN<<4];
struct query
{
    int x,op;
    int l,r,k;
    int fin;
    bool operator <(const query& a)const{
        if (fin!=a.fin) return fin<a.fin;
        return x<a.x;
    }
}ques[MAXN<<2],q1[MAXN<<2],q2[MAXN<<2];
int ans[MAXN<<2];
char ch[4000000],chout[1000000],*pout=chout,*ptr=ch;
void in(int &x){
    x=0;
    while(*ptr<48) ptr++;
    while(*ptr>47) x=x*10+*ptr++-48;
}
void out(int x){
    if(!x)*pout++=‘0‘;
    int p=0;char buf[10];
    while(x) buf[++p]=x%10+‘0‘,x/=10;
    while(p) *pout++=buf[p--];
    *pout++=‘\n‘;
}
void add(int i,int x)
{
    while (i<=n) tree[i]+=x,i+=i&-i;
}
int query(int l,int r)
{
    int ret=0;
    while (r) ret+=tree[r],r-=r&-r;
    while (l) ret-=tree[l],l-=l&-l;
    return ret;
}
inline void solve(int L,int R,int l,int r)
{
    if (l>r) return;
    if (L==R)
    {
        for (int i=l;i<=r;i++) ans[ques[i].x]=a[L];
        return;
    }
    int Mid=l-1,mid=(L+R)>>1,tp1=0,tp2=0;
    for (int i=l;i<=r;i++)
    {
        if (ques[i].op==1)
        {
            if (ques[i].k<=a[mid]) add(ques[i].l,1),ques[i].fin=1,q1[++tp1]=ques[i];
            else ques[i].fin=0,Mid++,q2[++tp2]=ques[i];
        }
        else
        {
            int temp=query(ques[i].l-1,ques[i].r);
            if (ques[i].k<=temp) ques[i].fin=1,q1[++tp1]=ques[i];
            else ques[i].k-=temp,ques[i].fin=0,Mid++,q2[++tp2]=ques[i];
        }
    }
    for (int i=l;i<=r;i++) if (ques[i].op==1&&ques[i].k<=a[mid]) add(ques[i].l,-1);
    tp2=0,tp1=0;
    for (int i=l;i<=Mid;i++) ques[i]=q2[++tp2];
    for (int i=Mid+1;i<=r;i++) ques[i]=q1[++tp1];
    solve(L,mid,Mid+1,r);
    solve(mid+1,R,l,Mid);
}
int main()
{
    freopen("kth.in","r",stdin);
    freopen("kth.out","w",stdout);
    fread(ptr,1,4000000,stdin);
    in(n),in(m);
    for (int i=1;i<=n;i++)
    {
        in(ques[i].k);
        ques[i].l=ques[i].r=i;
        a[i]=ques[i].k;
        ques[i].x=i;
        ques[i].op=1;
    }
    sort(a+1,a+n+1);
    for (int i=n+1;i<=n+m;i++)
    {
        ques[i].op=2;
        in(ques[i].l);in(ques[i].r);in(ques[i].k);
        ques[i].x=i;
    }
    solve(1,n,1,n+m);
    for (int i=n+1;i<=n+m;i++) out(ans[i]);
    fwrite(chout,1,pout-chout,stdout);
}
时间: 2024-12-26 17:20:58

【2012河南省队互测】【COGS930】找第k小的数的相关文章

cogs930.[河南省队2012] 找第k小的数

930. [河南省队2012] 找第k小的数 ★★★   输入文件:kth.in   输出文件:kth.out   简单对比 时间限制:1 s   内存限制:128 MB 题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M.第二行N个数,表示序列A1,A2,...,AN.紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj

【COGS 1534】 [NEERC 2004]K小数 &amp;&amp;【COGS 930】 [河南省队2012] 找第k小的数 可持久化01Trie

板子题,只是记得负数加fix最方便 #include <cstdio> const int A=19,N=100010; namespace FIFO { char ch,B[1<<20],*S=B,*T=B; #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<20,stdin),S==T)?0:*S++) #define isd(c) (c>='0'&&c<='9') int aa,bb

分治法题目整理分析 找第k小的数/求逆序对数目/派

设计一个平均时间为O(n)的算法,在n(1<=n<=1000)个无序的整数中找出第k小的数. 提示:函数int partition(int a[],int left,int right)的功能是根据a[left]~a[right]中的某个元素x(如a[left])对a[left]~a[right]进行划分,划分后的x所在位置的左段全小于等于x,右段全大于等于x,同时利用x所在的位置还可以计算出x是这批数据按升非降序排列的第几个数.因此可以编制int find(int a[],int left,

两个有序数组,找第k小的数//未完

1.题目描述:a,b两个有序数组,找出第k小的数,logk,二分查找,1个小于怎么办? 2.思路: 对于数组A . B , 如果 B[pb] < A[pa] && B[pb] > A[pa - 1], 那么 B[pb] 一定是第 pa + pb + 1  小的数.比如数组A = {1, 8, 10, 20}, B = {5, 9, 22, 110},pa = 2, pb = 1, 这时,(B[pb] = 9) < (A[pa] =10) && (B[pb]

COGS 930. [河南省队2012] 找第k小的数

题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M. 第二行N个数,表示序列A1,A2,...,AN. 紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj中第k小的数等于多少. 输出格式 共输出M行,第i行输出第i个询问的答案. 样例输入1: 4 3 4 1 2 3 1 3 1 2 4 3 1 4 4 样例输出1: 1

COGS 930. [河南省队2012] 找第k小的数 主席树

主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 #define MAX 2000005 using namespace std; int sum[MAX],l[MAX],mid[MAX],r[MAX],a[MAXN],b[MAXN],n,m,sz,size,root[MAXN],cnt; void build(int &x,int z,int y

[河南省队2012] 找第k小的数

★★☆   输入文件:kth.in   输出文件:kth.out   简单对比时间限制:1 s   内存限制:128 MB 题目描述 看到很短的题目会让人心情愉悦,所以给出一个长度为N的序列A1,A2,A3,...,AN, 现在有M个询问,每个询问都是Ai...Aj中第k小的数等于多少. 输入格式 第一行两个正整数N,M. 第二行N个数,表示序列A1,A2,...,AN. 紧着的M行,每行三个正整数i,j,k(k≤j-i+1),表示 询问Ai...Aj中第k小的数等于多少. 输出格式 共输出M行

算法导论:快速找出无序数组中第k小的数

题目描述: 给定一个无序整数数组,返回这个数组中第k小的数. 解析: 最平常的思路是将数组排序,最快的排序是快排,然后返回已排序数组的第k个数,算法时间复杂度为O(nlogn),空间复杂度为O(1).使用快排的思想,但是每次只对patition之后的数组的一半递归,这样可以将时间复杂度将为O(n). 在<算法导论>有详细叙述 这里主要用C++实现,实现思路就是先选取当前数组的第一个数作为"主轴",将后面所有数字分成两部分,前面一部分小于"主轴",后面一部

无序数组中找第k大的数

类快排算法 由于只要求找出第k大的数,没必要将数组中所有值都排序. 快排中的partition算法,返回key在数组中的位置的cnt(相对于left的偏移量),如果cnt正好等于k,那么问题则得到解决:如果cnt小于k,去左边找第k个:如果cnt>k,则去右边找第k-cnt个.直到key的位置等于k-1,则找对问题的解. /*快排中的划分算法*/ int partition(int* input, int low, int high) { int tmp = input[low]; // 取一个