2025年11月29日训练赛

P13968 [VKOSHP 2024] Classics

倒着找每个的最终位置,二分+树状数组求第k大,这样把序列搞出来
再找最长上升子序列,从小往大往树状数组里面加,找前面的最长上升子序列+1 不可以从前往后往树状数组里加,找比他小的的最长上升子序列+1,加入的顺序不对

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define yes cout << "Yes" << endl
#define no cout << "No" << endl
#define pii pair<int,int>
#define ll long long
#define pb push_back
#define ft first
#define se second
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f

#define int long long

const int N = 200010;int n;
int p[N], mp[N], a[N];
int lowbit(int x){return x&(-x);}
int tr1[N]; 
void add1(int x, int k){
    for(int i = x; i <= n; i += lowbit(i)) tr1[i] += k;
}
int ask1(int x){
    int res = 0; for(int i = x; i > 0; i -= lowbit(i)) res += tr1[i]; return res;
}

int tr2[N];
void add2(int x, int k){
    for(int i = x; i <= n; i += lowbit(i)) tr2[i] = max(tr2[i], k); 
}
int ask2(int x){
    if(!x) return 0;
    int res = 0;
    for(int i = x; i > 0; i -= lowbit(i)) res = max(res, tr2[i]); return res;
}

void solve(){
    cin >> n;

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

    for(int i = 1; i <= n; i ++) add1(i, 1);
    for(int i = n; i >= 1; i --){
        int x = a[i];
        int l = 1; int r = n;
        while(l < r){
            int mid = (l + r) >> 1;
            if(ask1(mid) >= x) r = mid;
            else l = mid + 1;
        }
        //cout << "get" << l << '\n';
        p[l] = i;
        mp[i] = l;
        add1(l, -1);
    }
// for(int i = 1; i <= n; i ++) cout << p[i] << ' '; cout << '\n';
    
    int ans = 1;
    for(int i = 1; i <= n; i ++){
        int t = ask2(mp[i] - 1) + 1;
        ans = max(ans, t);
        cout << ans << '\n';
        add2(mp[i], t);

    }
    
}

signed main(){
  std::ios::sync_with_stdio(false);
    int T = 1;// cin >> T;
    while(T--){
        solve();
    }
}
posted @ 2025-12-04 17:29  arin876  阅读(17)  评论(0)    收藏  举报