杭电 5592 ZYB's Premutation(线段树求第k大数)

本文介绍了一种通过已知排列前缀区间的逆序对数量来还原原始排列的方法,包括输入数据处理、预处理算法以及具体实现代码。

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

BC的描述:

问题描述
ZYBZYBZYB有一个排列PPP,但他只记得PPP中每个前缀区间的逆序对数,现在他要求你还原这个排列.

(i,j)(i<j)被称为一对逆序对当且仅当Ai>Aj
输入描述
第一行一个整数TTT表示数据组数。

接下来每组数据:

第一行一个正整数NNN,描述排列的长度.

第二行NNN个正整数Ai,描述前缀区间[1,i]的逆序对数.

数据保证合法.

1≤T≤51,1≤N≤500001.
输出描述
TTT行每行NNN个整数表示答案的排列.
输入样例
1
3
0 1 2
输出样例
3 1 2


假设原数组为a数组,给你的是b数组,b[i]代表在a数组中从第一个数到第i个数的逆序对的个数,则s = b[i] - b[i-1]即为在a数组中第i个数与前面的数构成逆序对的个数,也就是说前i-1个数中有s个数比第i个数大,则a[i]即为数组中第s+1大的数;

所以需要先预处理一下b数组,从n开始向1循环 b[n] -= b[n-1];

将处理过的b数组,从n开始循环,此时,b[i]代表在a数组中前面有b[i]个数比a[i]大,所以只需要找第k大数就可以了;

代码如下:


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
const int N = 5e4+10;
struct SegmentTree
{
    int l, r, x, sum;
};

SegmentTree Tree[4*N];
int n, m;
int p[N],f[N];

void UpdateUp(int k)
{
    Tree[k].sum = Tree[k<<1].sum + Tree[k<<1|1].sum;
}

void build(int l, int r, int k)
{
    Tree[k].l = l, Tree[k].r = r;
    if(l==r)
    {
        Tree[k].x = m --, Tree[k].sum = 1;
        return ;
    }
    int mid = (l+r) >> 1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    UpdateUp(k);
}

void query(int k, int n,int &s)
{
    if( Tree[k].l == Tree[k].r && n==1)
    {
        Tree[k].sum = 0;
        s = Tree[k].x;
        return ;
    }
    if(n <= Tree[k<<1].sum)
        query(k<<1, n, s);
    else
        query(k<<1|1 , n - Tree[k<<1].sum, s);
    UpdateUp(k);
}

void test()
{
    scanf("%d",&n);
    m = n;
    build(1,n,1);
    long long sum = 0;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&p[i]);
        p[i] -= sum, sum += p[i];
    }
    for(int i=n; i>=1; i--)
        query(1, p[i]+1, f[i]);
    for(int i=1; i<=n; i++)
        printf(i==n?"%d\n":"%d ",f[i]);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
        test();
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值