https://ac.nowcoder.com/acm/problem/14893

说一下这题用树状数组的解法

树状数组是比较暴力直观的想法,也是我读完题的第一个想法。它不是最好的解法

第一步,贪心思想

首先还是贪心的思想,对于每一次入栈之后,设t为栈顶元素,那么就要判断这个时候取t是不是最优解,如何判断最优解呢?

如果比t大的数已经在栈中出现过(也就是已经输入过),那么此时取t就是最好的情况,否则在答案中这一位置上的数就会更小,那就不是字典序最大了,就不是最优解了。此时就要让t出栈,答案数组res就要push_back(t)。注意这是一个循环。我写了一个while循环。

否则,就继续入栈。

第二步,树状数组的想法

第一步中提到 “如果比t大的数已经在栈中出现过(也就是已经输入过)” 这句话,那么我们就要用一个数据结构存这个信息。用数组作映射,下标为1~n中的数,对应的值应该是大于等于下标的数出现的次数。这个数组名字为v。那么如果v[i]==i,那么栈顶元素t出栈。所以每次入栈的时候,也就是输入的时候,都涉及到v数组的改动。我们发现这是一个区间修改+单点查询。所以,树状数组,启动!!

```//附上代码,写的不太好
#include<bits/stdc++.h>
using namespace std;
#define int long long

int tree[1000001]={0};
vector<int>res;
int n;
    
int lowbit(int x){
    return x&(-x);
}
int sum(int x){
    int ans=0;
    while(x>0){
        ans+=tree[x];
        x-=lowbit(x);
    }
    return ans;
}
void update(int x,int d){
    while(x<=n){
        tree[x]+=d;
        x+=lowbit(x);
    }
}
//以上为树状数组
signed main(){
    cin>>n;
    vector<int>v(n+1,0);
//其实可以不用数组v,因为初始化每个元素都为0,
//树状数组有差分的思想,原数组v其实没什么用。
   
    for(int i=1;i<=n;i++){
        update(i,v[i]);
    }
    vector<int>sta;//栈,用vector代替
    for(int i=0;i<n;i++){
        int t;
        cin>>t;
        sta.push_back(t);
        update(1,1);
        update(t+1,-1);
        while(!sta.empty()){
            if(sum(t)==n-t+1){
                sta.pop_back();
                res.push_back(t);
            }
            else break;
            t=sta.back();
        }
    }
    for(int i=0;i<res.size();i++){
        cout<<res[i]<<" ";
    }
}
注:未经许可不可转载