HDU 5592 ZYB's Premutation 线段树(查找动态区间第K大)

</pre><pre class="html" name="code">
ZYB有一个排列PPP,但他只记得PPP中每个前缀区间的逆序对数,现在他要求你还原这个排列.

一对数(i,j)当(i<j)时被认为是逆序对。
​​

输入描述
第一行一个整数TTT表示数据组数。

接下来每组数据:

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

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

数据保证合法.

1≤T≤51 \leq T \leq 51≤T≤5,1≤N≤500001 \leq N \leq 500001≤N≤50000

输出描述
TTT行每行NNN个整数表示答案的排列.

输入样例
1
3
0 1 2

输出样例
3 1 2




树的节点保存三个值:左端点a,右端点b,该区间剩下的数字的个数sum。
查询第k大的时候,当k大于右子节点的sum,则查询左子节点第(k-右子节点的sum)大,否则查询右子节点,当左端点等于右端点时返回。

#include <stdio.h>
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

struct Tree
{
    int a,b,sum;
}t[200000];

void init(int x,int y,int num)
{
    t[num].a=x;
    t[num].b=y;
    if(x==y)
    {
        t[num].sum=1;
        return;
    }
    int mid=(x+y)/2;
    init(x,mid,num<<1);
    init(mid+1,y,(num<<1)+1);
    t[num].sum=t[num<<1].sum+t[(num<<1)+1].sum;
}

int query(int x,int num)
{
    t[num].sum--;
    if(t[num].a==t[num].b) return t[num].a;
    if(x>t[(num<<1)+1].sum) return query(x-t[(num<<1)+1].sum,(num<<1));
    else return query(x,(num<<1)+1);
}


int main()
{
    int n,T;
    int a[50005],b[50005];
    while(~scanf("%d",&T))
    {
        while(T--)
        {
            scanf("%d",&n);
            init(1,n,1);
            for(int i=0; i<n; i++)
            {
                scanf("%d",&a[i]);
            }
            //  for(set<int>::iterator it=se.begin();it!=se.end();it++) printf("%d ",*it);
            for(int i=n-1; i>0; i--)
            {
                int temp=a[i]-a[i-1];
                b[i]=query(temp+1,1);
            }
            b[0]=query(1,1);
            for(int i=0; i<n; i++)
                if(!i) printf("%d",b[i]);
                else printf(" %d",b[i]);
            printf("\n");
        }
    }
}


发布了3 篇原创文章 · 获赞 0 · 访问量 943
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览