cf1262D2 Optimal Subsequences (Hard Version)(二分答案+bit)

该博客介绍了如何解决一道编程竞赛题目,即在给定序列a上进行m个询问,寻找[0, k]区间内的第pos小元素。由于询问是从0开始的,所以需要特别处理。解题策略是按k排序询问,使用树状数组存储前ki个数,通过二分查找找到满足条件的最小mid值,达到O(nlog^2n)的时间复杂度。博主认为可能有更快的解决方案,但尚未深入探究。" 119052849,11244828,Ansible变量管理与使用,"['Ansible', '配置管理', '自动化工具', 'YAML', '变量']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解法:

转换题意后,这题就是给定一个序列a,给出m个询问,问[0,k]的第pos小的数.

特殊就特殊在是从0开始的。

可以保存询问,我们让不同的询问ki从小到大排列,从小到大枚举k,将前ki个数存入树状数组,这时候可以通过二分答案来枚举答案mid,查询小于等于mid的数num,找出num=pos的最小的mid,就是第pos小的数了。

时间复杂度是O(nlog^2n)

应该能更快...还没去想

 

#include <bits/stdc++.h>

using namespace std;
const int maxn=2e5+5;
struct node
{
    int x, y;
}a[maxn], b[maxn];
int c[maxn];
int bit[maxn];
int cmp(node a, node b)
{
    if(a.x>b.x)return 1;
    else if(a.x==b.x)
    {
        if(a.y<b.y)return 1;
        else return 0;
    }
    else return 0;
}


int lowbit(int x)
{
    return x&(-x);
}
int add(int x, int y)
{
    for(int i=x; i<maxn; i+=lowbit(i))bit[i]+=y;
}
struct query{
    int k, pos, id;
}q[maxn];
int cmp2(query a, query b)
{
    return a.k<b.k;
}

int sum(int x)
{
    int sum=0;
    for(int i=x; i>0; i-=lowbit(i))sum+=bit[i];
//    printf("sum\n");
    return sum;
}
int ans[maxn];
int main()
{
    int t, i, j, n, m;

        scanf("%d", &n);
        for(i=0; i<n; i++)
        {
            scanf("%d", &a[i].x);
            c[i]=a[i].x;
            a[i].y=i;
        }
        sort(a, a+n, cmp);
//        for(i=0; i<n; i++)printf("%d\n", a[i].x);
        scanf("%d", &m);
        for(i=0; i<m; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            q[i].k=x,q[i].pos=y, q[i].id=i;;
        }
        sort(q, q+m, cmp2);
        int k=0;
        for(i=0; i<m; i++)
        {

            while(k<q[i].k)
            {
//                printf("k%d\n", k);
                add(a[k].y+1, 1);
//                printf("k%d\n", k);
                k++;
            }
//            printf("i%d\n", i);
            int mid, l=1, r=maxn-2,mi=maxn;
            for(j=0; j<100; j++)
            {
                mid=(l+r)>>1;
                if(sum(mid+1)>=q[i].pos)
                {
                    mi=min(mi, mid);
                    r=mid-1;
                }
                else l=mid+1;
            }
            ans[q[i].id]=mi;
        }
        for(i=0; i<m; i++)
        {
            printf("%d\n", c[ans[i]]);
        }

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值