hdu5592&bestcoder Round #65 1003題

題目大意:

ZYB's Premutation

Accepts: 218
Submissions: 983
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 131072/131072 K (Java/Others)
問題描述
ZYBZYB有一個排列PPP,但他只記得PPP中每個前綴區間的逆序對數,現在他要求你還原這個排列.

(i,j)(i<j)(i,j)(i < j)被稱爲一對逆序對當且僅當Ai>AjA_i>A_j
輸入描述
第一行一個整數TTT表示數據組數。

接下來每組數據:

第一行一個正整數NN,描述排列的長度.

第二行NN個正整數AiA_i,描述前綴區間[1,i][1,i]的逆序對數.

數據保證合法.

1≤T≤5,1≤N≤500001 \leq N \leq 50000
輸出描述
TT行每行NN個整數表示答案的排列.
輸入樣例
1
3
0 1 2
輸出樣例
3 1 2

這題是個cf的原題,要利用結點的數據,來找區間的標記。考的很靈活。
解題思路:
      利用線段樹求逆序數,還原整個排列。首先設fif_i是第ii個前綴的逆序對數,pip_i是第ii個位置上的數,
則fi−fi−1ii前面比pip_i大的數的個數.我們考慮倒着做,當我們處理完iii後面的數,第iii個數就是剩下的數中
第fi−fi−1+1f_i-f_{i-1}+1大的數。再利用線段樹。
      首先線段樹每個結點表示的是區間長度。每次查詢線段樹,先訪問右區間,因爲右區間裏表纔是表示倒着數的大的數,若右區間的此時的長度不夠fi−fi−1+1,
說明此時這個數不在左邊的區間,則去查詢左邊區間。但要右邊減去區間的長度。因爲此時找的是左邊的區間第幾大的數,直到找到葉子結點。記錄它的左端點,就是當前
第的位置應該放的數。
     
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=50000+1000;
int a[maxn],ans[maxn],t,n,p;
int sum[maxn<<4];

void build(int o,int L,int R)
{
    int M=L+(R-L)/2;
    if(L==R)      sum[o]=1;
    else
    {
        build(o*2,L,M);
        build(o*2+1,M+1,R);
         sum[o]=sum[o*2]+sum[o*2+1];
    }
}

int query(int o,int L,int R,int p)
{
        int M=L+(R-L)/2;
        if(L==R)
        {
                sum[o]=0;
                return L;
        }
        int ret;
        if(sum[o*2+1]>=p)
                ret=query(o*2+1,M+1,R,p);
        else
                ret=query(o*2,L,M,p-sum[o*2+1]);//右區間要剪掉此時左邊的值
        sum[o]=sum[o*2]+sum[o*2+1];//更新當前結點
        return ret;
}

int main()
{
        scanf("%d",&t);
        while(t--)
        {
           scanf("%d",&n);
           for(int i=1;i<=n;i++)
              scanf("%d",a+i);
         build(1,1,n);
         a[0]=0;
           for(int i=n;i>=1;i--)
           {
                 int p=a[i]-a[i-1];
                  ans[i]=query(1,1,n,p+1);//加1注意
           }
           for(int i=1;i<=n;i++)
                printf("%d%c",ans[i],i==n?'\n':' ');
        }
        return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章