HDU 5592 ZYB's Premutation

题目链接

传送门

题意

对于一个一到 n 的序列,给出他的逆序数的前缀和,求这个序列。

分析

我们倒着来考虑, a[1] a[n] 的逆序数为 sum[n] ,那么 sum[n]sum[n1]=k 表示的是 a[1] a[n1] 有k个数大于 a[n] 那么 a[n] 就是这个序列的第 k+1 大的数,题目就转化成求数组的动态第 k 大。

Code

#include 
#include 
#include 
#include 
#define lson num<<1
#define rson num<<1|1
#define gl l,m,lson
#define gr m+1,r,rson
#define PARA int l,int r,int num
using namespace std;
const int MAXN = 5e4+100;
struct SegTree {
    int st[MAXN<<2];
    void init() {
        memset(st,0,sizeof(st));
    }
    void update(int pos,int v,PARA) {
        int m = l+r>>1;
        if(l==r)
            st[num]+=v;
        else {
            if(m>=pos)
                update(pos,v,gl);
            else
                update(pos,v,gr);
            st[num]=st[lson]+st[rson];
        }
    }
    int find(int k,PARA) {
        if(l==r)
            return l;
        int m = l + r >> 1;
        if(st[rson]>=k)
            return find(k,gr);
        else
            return find(k-st[rson],gl);
    }
} S;

int a[MAXN];

int main() {
    int t,n;
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        S.init();
        a[0]=0;
        for(int i=1; i<=n; i++) {
            scanf("%d",a+i);
            S.update(i,1,1,n,1);
        }
        vector<int >ans;
        for(int i=n; i>=1; i--) {
            int k=a[i]-a[i-1]+1;
            int val=S.find(k,1,n,1);
            ans.push_back(val);
            S.update(val,-1,1,n,1);
        }
        for(int i=n-1; i>0; i--)
            printf("%d ",ans[i]);
        printf("%d\n",ans[0]);
    }
    return 0;
}

你可能感兴趣的:(线段树&&树状数组)