1. 程式人生 > >【LG4309】【BZOJ3173】[TJOI2013]最長上升子序列

【LG4309】【BZOJ3173】[TJOI2013]最長上升子序列

【LG4309】【BZOJ3173】[TJOI2013]最長上升子序列

題面

洛谷
BZOJ

題解

插入操作顯然用平衡樹就行了
然後因為後面的插入對前面的操作無影響
就直接在插入完的序列上用樹狀陣列求下每個點為終點的最長上升子序就行了
然而懶得手寫平衡樹了
直接用了\(rope\)
rope用法
程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/rope> 
using namespace std; 
using namespace __gnu_cxx; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = getchar();
    if (ch == '-') w = -1 , ch = getchar();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    return w * data;
} 
#define MAX_N 100005 
rope<int> seq; 
int N, ans[MAX_N]; 
int c[MAX_N]; 
inline void chkmax(int &x, int y) { if (x < y) x = y; } 
inline int lb(int x) { return x & -x; } 
void add(int x, int v) { while (x <= N) chkmax(c[x], v), x += lb(x); } 
int sum(int x) { int res = 0; while (x > 0) chkmax(res, c[x]), x -= lb(x); return res; } 

int main () { 
    N = gi(); 
    for (int i = 1, t; i <= N; i++) t = gi(), seq.insert(t, i); 
    for (int i = 0, t; i < N; i++) t = seq[i], add(t, ans[t] = sum(t) + 1); 
    for (int i = 1; i <= N; i++) chkmax(ans[i], ans[i - 1]), printf("%d\n", ans[i]); 
    return 0; 
}