nth-element

给定一个长度为 ​N 的整数数组。你的程序需要按照输入顺序处理如下两种操作:

     1.修改。修改操作带有两个参数 ​p 和 x ​,表示将数组中下标为 p​ 的元素修改为 x ​;

     2.查询。查询操作带有三个参数 ​L,R和 k ​,表示查询数组中从下标为 ​L 的元素开始到下标为 ​R 的元素为止(两端均包含)的这个子数组中数值从小到大排第 ​k 的整数。

输入描述

测试用例输入第一行为一个整数N [1,1000 000] ​,表示数组的长度。

第二行为 ​N 个以空格分隔的整数,表示初始数组的每一项。

第三行为一个整数 Q  [100 000],表示操作的数量。

从第四行开始的 Q​ 行,每行包含若干个以空格分隔的整数。其中第一个整数表示操作的类型,1表示修改操作,2表示查询操作;若操作为修改操作,接下来包含两个整数p,x (0<=p<N 0<=x<=1 000 000 000 ) ​,含义如前述所示;若操作为查询操作,接下来包含三个整数 ​L,R和 k (0<=L<=R<N  1<=k<=R-L+1)​,含义如前述所示。

保证数组中的每个元素在任意时刻均在 ​[0,1 000 000 000]范围内。

保证所有查询中子数组的长度之和不超过40 000 000 ​。

输出描述

对于输入中的每一个查询操作,你的程序应该在单独的一行上输出查询的结果。

样例说明

对于题目中给出的样例,其第一个操作为 2 1 3 2,表示查询下标从 1 - 3 范围内,即数组 [2, 3, 4] 中数值排名第二大的元素,即为 3;第二个操作为 1 2 2,表示修改下标为 2 的元素为 2;第三个操作为2 1 3 2,表示查询下标从 1 - 3 范围内,即数组 [2, 2, 4] (注意此时下标为 2 的元素已经被修改为 2)中数值排名第二大的元素,即为 2。

注意,计算排名时,相同的整数要进行重复计算。例如样例中的 [2, 2, 4],计算排名时 2 排第 1 和 2,4 排第 3。

  测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 5↵
  2. 1 2 3 4 5↵
  3. 3↵
  4. 2 1 3 2↵
  5. 1 2 2↵
  6. 2 1 3 2↵
以文本方式显示
  1. 3↵
  2. 2↵
1秒 64M 0
#include<stdio.h>  
#include<stdlib.h>  

//初学时写的代码,非常冗杂
  
int min(int a,int b,int c,int l,int mid,int r)  
{  
    int q[3]={a,b,c},i,temp,j;  
    for(i=0;i<2;i++)  
    {  
        for(j=i;j<2;j++)  
        {         
            if(q[i]>q[i+1])  
            {  
                temp=q[i];  
                q[i]=q[i+1];  
                q[i+1]=temp;  
            }             
        }         
    }  
    if(q[1]==a) return l;  
    if(q[1]==b) return mid;  
    if(q[1]==c) return r;  
}  
  
int quickselect(int c[],int l,int r,int k)  
{  
    int p,j,i,temp; //HoarePartition  
    int mid,need;  
    mid=(l+r)/2;  
    need=min(c[l],c[mid],c[r],l,mid,r); //找到头c[l]、尾c[r]、中c[mid]三数的中值的下标 need  
    //这里随机选取中轴更好
    temp=c[need];  
    c[need]=c[l];  
    c[l]=temp;    //调换c[need],c[l]   
      
    p=c[l]; //中轴   
    i=l;  
    j=r+1;  
    do  
    {  
        do  
        {  
            i++;  
        }while(c[i]<p);  
        do  
        {  
            j--;  
        }while(c[j]>p);  
        temp=c[i];  
        c[i]=c[j];  
        c[j]=temp;  
    }while(i<j);  
    temp=c[i];  
    c[i]=c[j];  
    c[j]=temp;   
    temp=c[l];  
    c[l]=c[j];  
    c[j]=temp;  
      
    if(j==l+k-1) return c[j];  
    else if(j>l+k-1) quickselect(c,l,j-1,k);  
    else quickselect(c,j+1,r,l+k-1-j);   
}   
  
  
int main(){  
    int n,i,m,t,j,result;  
    scanf("%d",&n);  
    int a[n];  
    for(i=0;i<n;i++) scanf("%d",&a[i]);  
    scanf("%d",&m);  
    int b[m][4];  
    for(i=0;i<m;i++)  
    {  
        scanf("%d",&b[i][0]);  
        if(b[i][0]==1) t=2;  
        else t=3;  
        for(j=1;j<=t;j++) scanf("%d",&b[i][j]);  
    }  
    int l,r,k,u;  
    if(n>100000)  //这里根据n的大小决定开静态数组还是动态数组完全是初学时多余的操作,开个全局数组就好了
    {  
        int *c;  
        int nc;  
        for(i=0;i<m;i++)  
        {         
            if(b[i][0]==1) a[b[i][1]]=b[i][2];  //alter  
            if(b[i][0]==2)  //inquire  
            {  
                l=b[i][1];  
                r=b[i][2];  
                k=b[i][3];  
                nc=r-l+1;  
                c=(int*)malloc(nc*sizeof(int));  
                for(j=l,u=0;j<=r;j++,u++)    c[u]=a[j];  
                result=quickselect(c,0,u-1,k);  
                free(c);  
                printf("%d\n",result);  
            }  
        }  
    }  
    else  
    {  
        int c[n];   
        for(i=0;i<m;i++)   
        {   
            if(b[i][0]==1) a[b[i][1]]=b[i][2];  //alter   
            if(b[i][0]==2)  //inquire   
            {   
                l=b[i][1];   
                r=b[i][2];   
                k=b[i][3];   
                for(j=l,u=0;j<=r;j++,u++)    c[u]=a[j];   
                result=quickselect(c,0,u-1,k);   
                printf("%d\n",result);   
            }   
       }      
    }  
      
}  
发布了19 篇原创文章 · 获赞 1 · 访问量 159

猜你喜欢

转载自blog.csdn.net/CN_BIT/article/details/104651332