题描述

有n头奶牛,已知它们的身高为 1~n 且各不相同,但不知道每头奶牛的具体身高。

现在这nn头奶牛站成一列,已知第i头牛前面有AiAi头牛比它低,求每头奶牛的身高。

输入格式
第1行:输入整数nn。

第2..n行:每行输入一个整数AiAi,第i行表示第i头牛前面有AiAi头牛比它低。
(注意:因为第1头牛前面没有牛,所以并没有将它列出)

输出格式
输出包含nn行,每行输出一个整数表示牛的身高。

第ii行输出第ii头牛的身高。

数据范围
1≤n≤105

样例

输入样例:
5
1
2
1
0
输出样例:
2
4
5
3
1


算法1

树堆
每次找第a[i] 大的数据 同时不能与后面出现的冲突

C++ 代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
#define fir first
#define sec second
const int maxn=1e5+10;

int siz[maxn];
int s[maxn][3];
int w[maxn],pos[maxn];
int tot;

void up(int i) {
    siz[i]=siz[s[i][0]]+siz[s[i][1]]+1;
}

void spin(int &i,int p) {
    int t=s[i][p];
    s[i][p]=s[t][!p],s[t][!p]=i,up(i),up(t),i=t;
}

void ins(int x,int &i) {
    if(!i) {
        i=++tot,siz[i]=1,w[i]=x,pos[i]=rand();
        return;
    }
    siz[i]++;
    if(x<=w[i]) {
        ins(x,s[i][0]);
        if(pos[s[i][0]]<pos[i])spin(i,0);
    } else {
        ins(x,s[i][1]);
        if(pos[s[i][1]]<pos[i])spin(i,1);
    }
}

void del(int x,int &i) {
    if(w[i]==x) {
        if(s[i][0]*s[i][1]==0) {
            i=s[i][0]+s[i][1];
            return;
        }
        if(pos[s[i][0]]>pos[s[i][1]]) {
            spin(i,1);
            del(x,s[i][0]);
        } else {
            spin(i,0);
            del(x,s[i][1]);
        }
    } else if(w[i]>x)del(x,s[i][0]);
    else del(x,s[i][1]);
    up(i);
}

int find(int x,int i) {
    if(!i)return 1;
    if(w[i]>=x)return find(x,s[i][0]);
    return find(x,s[i][1])+siz[s[i][0]]+1;
}

int ask(int x,int i) {
    if(siz[s[i][0]]==x-1)return w[i];
    if(siz[s[i][0]]>=x)return ask(x,s[i][0]);
    return ask(x-siz[s[i][0]]-1,s[i][1]);
}

int ans[maxn];
int a[maxn];
signed main() {
    int n;
    cin>>n;
    int root=0;

    ins(1,root);
    for(int i=2; i<=n; i++) cin>>a[i],ins(i,root),a[i]++;


    for(int i=n; i>1; i--) {
        ans[i]=ask(a[i],root);
        del(ans[i],root);
    }

    cout<<ask(1,root)<<endl;
    for(int i=2; i<=n; i++) {
        cout<<ans[i]<<endl;
    }
    return 0;
}

算法2

后面看主席树 觉得 权值线段树也能过去orz

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fastio ios::sync_with_stdio(false);cin.tie(0)
using namespace std;

const int maxn = 1e5 + 5;

int n, m;

int b[maxn << 2];

void push_up(int rt) {
    b[rt] = b[rt << 1] + b[rt << 1 | 1] ;
}

void update(int L, int l, int r, int rt, int c) {
    if(l == r) {
        b[rt] += c;
        return ;
    }
    int mid = l + r >> 1;
    if(L <= mid) update(L, l, mid, rt << 1, c);
    else update(L, mid + 1, r, rt << 1 | 1, c);
    push_up(rt);
}

void query(int L, int l, int r, int rt) {
    if(l == r) {
        cout << l << " " << b[rt] << endl; 
        return ;
    }
    int mid = l + r >> 1;
    if(L <= mid) query(L, l, mid, rt << 1);
    else query(L, mid + 1, r, rt << 1 | 1);
}

int find_k(int l, int r, int rt, int k) {
    if(l == r) {
        return l;
    }
    int mid = l + r >> 1;
    if(k <= b[rt << 1]) return find_k(l, mid, rt << 1, k);
    else return find_k(mid + 1, r, rt << 1 | 1, k - b[rt << 1]);
}

int a[maxn];
int ans[maxn];
int main() {
    fastio;
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        update(i, 1, n, 1, 1);
    }

    for(int i = 2; i <= n; i ++) {
        cin >> a[i];
    }
    a[1] = 0;
    int k = n;
    for(int i = n; i >= 1; i --) {
        ans[i] = find_k(1, n, 1, a[i] + 1);
    //    cout << find_k(1, n, 1, a[i] + 1) << endl;
    //    cout << "\\\\" << ans[i] << endl;
        update(ans[i], 1, n, 1, -1);
    //    query(ans[i], 1, n, 1);
    }

    for(int i = 1; i <= n; i ++)
        cout << ans[i] << endl; 

    return 0;
}

解法3

我听同学说了下 终于找到二分树状数组在搞什么了

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;

int c[maxn];
int n;

int query(int x){
    int res = 0;
    for(; x; x -= x&(-x)) res += c[x];
    return res;
}

void add(int x, int y){
    for(;x <= n; x += x & (-x)) c[x] += y;
}

int a[maxn];
int ans[maxn];
int main(){
    cin >> n;
    add(1, 1);
    a[1] ++;
    for(int i = 2; i <= n ; i ++ ) {
        cin >> a[i]; a[i] ++;
        add(i, 1);
    }
    for(int i = n; i >= 1; i -- ) {
        int l = 1, r = n + 1;
        while(r - l >= 1){
            int mid = l + r >> 1;
            if(query(mid) >= a[i]) r = mid;
            else l = mid + 1;
        }
        ans[i] = l;
        add(l, -1);

        // for(int i = 1; i <= n; i ++ )  {
        //     cout << query(i) << "  ";
        // }cout << endl;


    }
    for(int i = 1; i <= n; i ++ ) {
        cout << ans[i] << endl;
    }
    return 0;
}