题解 P5010 【HMR的LIS Ⅲ】
Solution
subtask 1
直接
subtask 3
求字典序最小的最长上升子序列
考虑求最长上升子序列的
实际上是开了一个数组,
最后贪心选即可
注意要倒着求
subtask 4
求字典序最小/次小/第三小的最长上升子序列
这个我除了正解不会别的做法
乱搞AC
subtask 2
其实如果知道了
令
显然可以
那么我们有了这两个数组之后,就可以求第 k 小了
肯定是要逐位确定
首先枚举
按照原下标排序,如果
那么就可以逐步确定,具体的做法是先按照
subtask 5
我们发现 subtask 2 的瓶颈在于求 f 和 g 数组。
对于 f 的转移
发现可以转移的是一段区间,所以那线段树维护就好了
代码:
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#define gc getchar
#define maxn 500010
#define cs const seg
//#define ll __int128
#define ll long long
#define INF 1000000000
#define pc putchar
using namespace std;
ll read(){
ll x = 0; bool f = 0; char c = gc();
while(!isdigit(c)){if(c == '-') f = 1; c = gc();}
while(isdigit(c)){x = x * 10 + c - '0'; c = gc();}
return f ? -x : x;
}
int st[maxn], top;
void write(ll x){
if(!x) pc('0'); top = 0;
while(x){st[++top] = x % 10; x /= 10;}
while(top) putchar(st[top--] + '0'); puts("");
}
int n, L, R; ll K;
int a[maxn], b[maxn * 3], c1, cnt;
void init_hash(){ c1 = n; a[0] = INF;
for(int i = 1; i <= n; ++i) b[i] = a[i] = read();
for(int i = 1; i <= n; ++i) b[++c1] = a[i] + L, b[++c1] = a[i] + R;
sort(b + 1, b + c1 + 1); cnt = unique(b + 1, b + c1 + 1) - b - 1;
}
inline int get_pos(int v){return lower_bound(b + 1, b + cnt + 1, v) - b;}
inline bool check(int x, int y){
if(x == INF) return 1;
return y - x > L && y - x < R;
}
#define lc i << 1
#define rc i << 1 | 1
struct seg{
int v, id; ll s;
seg(int _v = 0, ll _s = 0){v = _v; s = _s;}
}T[maxn * 12], A[maxn];
inline void maintain(seg &o, seg ls, seg rs){
o.v = max(ls.v, rs.v); o.s = 0;
if(ls.v >= rs.v && ls.v) o.s += ls.s;
if(ls.v <= rs.v && rs.v) o.s += rs.s;
o.s = max((ll)1, o.s); o.s = min(o.s, K + 1);
}
void update(int i, int l, int r, int k, cs &o){
if(l == r){
if(o.v > T[i].v) T[i] = o;
else if(o.v == T[i].v) T[i].s += o.s;
T[i].s = min(T[i].s, K + 1);
return ;
} int m = l + r >> 1;
if(k <= m) update(lc, l, m, k, o);
else update(rc, m + 1, r, k, o);
maintain(T[i], T[lc], T[rc]);
}
seg query(int i, int l, int r, int L, int R){
if(l > R || r < L) return seg(0, 0);
if(L <= l && r <= R) return T[i];
int m = l + r >> 1;
seg t, t1 = query(lc, l, m, L, R), t2 = query(rc, m + 1, r, L, R);
maintain(t, t1, t2); return t;
}
inline bool cmp(cs &u, cs &v){
if(u.v == v.v) return u.id < v.id;
return u.v > v.v;
}
int ans[maxn], c2;
int main(){
n = read(); K = read(); L = read(); R = read();
init_hash();
for(int i = n; i; --i){
A[i] = query(1, 1, cnt, get_pos(a[i] + L) + 1, get_pos(a[i] + R) - 1);
A[i].id = i; ++A[i].v;
update(1, 1, cnt, get_pos(a[i]), A[i]);
}
// for(int i = 1; i <= n; ++i) cerr << A[i].v << " " << A[i].s << endl;
sort(A + 1, A + n + 1, cmp); int p = 0, la = 0;
ll tot = 0;
for(int i = 1; i <= n; ++i) if(A[i].v == A[1].v) tot += A[i].s;
//write(tot);
for(int i = 1; i <= n; i = p){
p = i;
while(A[p].v == A[i].v) ++p;
for(int j = i; j < p; ++j){
if(A[j].id < la || !check(a[la], a[A[j].id])) continue;
if(A[j].s >= K){
ans[++c2] = A[j].id; la = A[j].id;
break;
}
K -= A[j].s;
}
}
cout << A[1].v << endl;
for(int i = 1; i <= c2; ++i) printf("%d ", ans[i]);
return 0;
}
rqy 的代码
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
typedef long long LL;
const int S = 10000000;
struct Read {
inline char gc() { static char buf[S], *p = buf, *end = buf; return p == end ? feof(stdin) ? (char)EOF : (end = buf + fread(p = buf, 1, S, stdin), *(p++)) : *(p++); }
template<typename T> Read &operator[](T &ans) { ans = 0; int c, f = 1; while (!isdigit(c = gc())) if (c == '-') f = -1; do ans = ans * 10 + c - '0'; while (isdigit(c = gc())); ans *= f; return *this; }
} read;
struct Write {
char obuf[S], *op, *oend; Write() { op = obuf; oend = obuf + S; }
inline void flush() { fwrite(obuf, 1, op - obuf, stdout); op = obuf; } inline void putChar(char c) { if (op == obuf) flush(); *(op++) = c; }
template <typename T> Write &operator[](T ans) { static int c[20]; int p = 0; while (ans) c[p++] = ans % 10, ans /= 10; while (p--) putChar(c[p] + '0'); return *this; }
Write &operator[](char c) { putChar(c); return *this; }
~Write() { flush(); }
} write;
const int N = 500050;
int n, m, L, R, A[N], NL[N], NR[N], B[N], f[N], hd[N], nxt[N], len; LL K, num[N];
void Discretize() { for (int i = 0; i < n; ++i) B[i] = A[i];
std::sort(B, B + n); m = std::unique(B, B + n) - B;
for (int i = 0; i < n; ++i) A[i] = std::lower_bound(B, B + m, A[i]) - B;
for (int i = 0, j = 0; i < m; NL[i] = j, ++i) while (j < m && B[j] <= B[i] + L) ++j;
for (int i = 0, j = 0; i < m; NR[i] = j, ++i) while (j + 1 < m && B[j + 1] < B[i] + R) ++j; }
struct Msg { int maxv; LL numv; Msg(int x = 0, LL v = 0) : maxv(x), numv(v) {}
inline void operator+=(const Msg &rhs) { if (maxv < rhs.maxv) maxv = rhs.maxv, numv = rhs.numv; else if (maxv == rhs.maxv) numv = std::min(K, numv + rhs.numv); }
} msgv[1200000];
void Modify(int x, int f, LL v) { Msg adv = Msg(f, v); for (x += len + 1; x; x >>= 1) msgv[x] += adv; }
Msg Query(int l, int r) { Msg ans = Msg(0, 1); if (l > r) return ans;
for (l += len, r += len + 2; l + 1 != r; l >>= 1, r >>= 1) { if (~l & 1) ans += msgv[l | 1]; if (r & 1) ans += msgv[r & ~1]; } return ans; }
int main() { read[n][K][L][R]; for (int i = 0; i < n; ++i) read[A[i]];
Discretize(); len = 1; while (len < m + 2) len <<= 1;
memset(hd, -1, sizeof hd);
for (int i = n - 1; i >= 0; --i) { Msg ans = Query(NL[A[i]], NR[A[i]]); Modify(A[i], f[i] = ans.maxv + 1, num[i] = ans.numv); nxt[i] = hd[f[i]]; hd[f[i]] = i; }
int ans1 = 0; while (~hd[ans1 + 1]) ++ans1; write[ans1]['\n'];
for (int i = ans1, last = -1, l = 0, r = m - 1; i; --i) for (int j = hd[i]; ~j; j = nxt[j]) if (j > last && A[j] >= l && A[j] <= r)
if (num[j] >= K) { write[(last = j) + 1][' ']; l = NL[A[j]]; r = NR[A[j]]; break; } else K -= num[j];
}