P4309 [TJOI2013]最长上升子序列
题面
题目链接
https://www.luogu.com.cn/problem/P4309
题目大意
给定一个序列,初始为空。
现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。
每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
解题思路
因为每次插入的数是按顺序从小到大的,所以我们可以从后往前计算
我们先用 vector 自带的 insert 函数得到所有数都插入完后的序列,然后从 n 到 1 依次计算
当计算完第 i 次操作的 Lis 后只要把 i 这个数的贡献去掉即可返回第 i - 1 次操作
然后就没有然后了。。。
以上步骤用 线段树 or 树状数组 维护都可
感觉挺水的一道题,不理解为什么会是紫题
AC_Coder 线段树
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; struct Tree { int l, r, lazy, maxn; } tree[N << 2]; void push_up(int rt) { tree[rt].maxn = max(tree[rt << 1].maxn, tree[rt << 1 | 1].maxn); } void push_down(int rt, int length) { if(tree[rt].lazy) { tree[rt << 1].lazy += tree[rt].lazy; tree[rt << 1 | 1].lazy += tree[rt].lazy; tree[rt << 1].maxn += tree[rt].lazy; tree[rt << 1 | 1].maxn += tree[rt].lazy; tree[rt].lazy = 0; } } void build(int l, int r, int rt, int *aa) { tree[rt].lazy = 0; tree[rt].l = l; tree[rt].r = r; if(l == r) { tree[rt].maxn = aa[l]; return; } int mid = (l + r) >> 1; build(l, mid, rt << 1, aa); build(mid + 1, r, rt << 1 | 1, aa); push_up(rt); } void update_range(int L, int R, int key, int rt) { if(tree[rt].r < L || tree[rt].l > R) return; if(L <= tree[rt].l && R >= tree[rt].r) { tree[rt].maxn += key; tree[rt].lazy += key; return; } push_down(rt, tree[rt].r - tree[rt].l + 1); int mid = (tree[rt].r + tree[rt].l) >> 1; if(L <= mid) update_range(L, R, key, rt << 1); if(R > mid) update_range(L, R, key, rt << 1 | 1); push_up(rt); } int query_max(int L, int R, int rt) { if(L <= tree[rt].l && R >= tree[rt].r) return tree[rt].maxn; push_down(rt, tree[rt].r - tree[rt].l + 1); int mid = (tree[rt].r + tree[rt].l) >> 1; int ans = -(0x3f3f3f); if(L <= mid) ans = max(ans, query_max(L, R, rt << 1)); if(R > mid) ans = max(ans, query_max(L, R, rt << 1 | 1)); return ans; } vector<int> vec, ans; int a[N], aa[N], n; signed main() { ios::sync_with_stdio(false); cin >> n; for(int i = 1; i <= n; i++) { int pos; cin >> pos; vec.insert(vec.begin() + pos, i); } for(int i = 1; i <= n; i++) a[i] = vec[i - 1]; build(1, n, 1, aa); for(int i = 1; i <= n; i++) { int val = a[i]; int ma = max(0, query_max(1, a[i] - 1, 1)); update_range(a[i], a[i], ma + 1, 1); } for(int i = n; i; i--) { int res = query_max(1, n, 1); ans.push_back(res); update_range(i, i, -0x3f3f3f, 1); } reverse(ans.begin(), ans.end()); for(auto i : ans) cout << i << '\n'; return 0; }
AC_Coder 树状数组
#include<bits/stdc++.h> using namespace std; const int N = 3e5 + 10; int n , tree[N] , a[N]; vector<int>vec , ans; int lowbit(int x) { return x & (-x); } void Add(int pos , int val) { while(pos <= N) { tree[pos] = max(tree[pos] , val) ; pos += lowbit(pos); } } int Get_max(int pos) { int res = 0 ; while(pos) { res = max(res , tree[pos]); pos -= lowbit(pos); } return res ; } signed main() { ios::sync_with_stdio(false); cin >> n; for(int i = 1 ; i <= n ; i ++) { int pos ; cin >> pos; vec.insert(vec.begin() + pos , i); } for(int i = 1 ; i <= n ; i ++) a[i] = vec[i - 1]; for(int i = 1 ; i <= n ; i ++) { int ma = Get_max(a[i]); Add(a[i] , ma + 1); } for(int i = n ; i ; i --) { int res = Get_max(i); ans.push_back(res); Add(i , -(0x3f3f3f3f)); } reverse(ans.begin() , ans.end()); for(auto i : ans) cout << i << '\n' ; return 0; }
凡所不能将我击倒的,都将使我更加强大