题目链接:洛谷
题目大意:对于一个长度为$n$的序列$a_i$,它的最长贪心严格上升子序列定义为(1)最长上升子序列(2)对于这个子序列,每个数的后继必须是在原序列中它右边第一个比它大的数。求所有长度为$k$的子区间中,它的最长贪心严格上升子序列的长度。
数据范围:$1leq kleq nleq 10^6,1leq a_ileq n$
我们注意到每个数的后继是唯一的,所以可以在数列后面加上一个$n+1$,然后它就是一个树结构。
然后直接用一个单调栈就可以建出来这棵树了。
那么这个最长贪心严格上升子序列的长度就是这个树上的最长链(只能从儿子到父亲)
如果在这个子区间内增加一个$a[x]$,那就是以$x$这个点的子树内的点为起点的最长贪心严格上升子序列都加上1,删除就是减去1。
就用一个线段树维护区间加,区间$max$就可以了。
1 #include<bits/stdc++.h> 2 #define Rint register int 3 using namespace std; 4 const int N = 1000003; 5 int n, k, p[N], stk[N], top, head[N], to[N], nxt[N], dfn[N], siz[N], tim; 6 inline void add(int a, int b){ 7 static int cnt = 0; 8 to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt; 9 } 10 inline void dfs(int x){ 11 dfn[x] = ++ tim; siz[x] = 1; 12 for(Rint i = head[x];i;i = nxt[i]) dfs(to[i]), siz[x] += siz[to[i]]; 13 } 14 int seg[N << 2], lazy[N << 2]; 15 inline void pushdown(int x){ 16 if(lazy[x]){ 17 seg[x << 1] += lazy[x]; 18 seg[x << 1 | 1] += lazy[x]; 19 lazy[x << 1] += lazy[x]; 20 lazy[x << 1 | 1] += lazy[x]; 21 lazy[x] = 0; 22 } 23 } 24 inline void pushup(int x){seg[x] = max(seg[x << 1], seg[x << 1 | 1]);} 25 inline void change(int x, int L, int R, int l, int r, int v){ 26 if(l <= L && R <= r){ 27 seg[x] += v; lazy[x] += v; 28 return; 29 } 30 int mid = L + R >> 1; 31 pushdown(x); 32 if(l <= mid) change(x << 1, L, mid, l, r, v); 33 if(mid < r) change(x << 1 | 1, mid + 1, R, l, r, v); 34 pushup(x); 35 } 36 int main(){ 37 scanf("%d%d", &n, &k); 38 for(Rint i = 1;i <= n;i ++) scanf("%d", p + i); 39 for(Rint i = 1;i <= n;i ++){ 40 while(top && p[stk[top]] < p[i]){ 41 add(i, stk[top]); -- top; 42 } 43 stk[++ top] = i; 44 } 45 while(top) add(n + 1, stk[top]), -- top; 46 dfs(n + 1); 47 for(Rint i = 1;i <= k;i ++) change(1, 1, n + 1, dfn[i], dfn[i] + siz[i] - 1, 1); 48 printf("%d", seg[1]); 49 for(Rint i = k + 1;i <= n;i ++){ 50 change(1, 1, n + 1, dfn[i], dfn[i] + siz[i] - 1, 1); 51 change(1, 1, n + 1, dfn[i - k], dfn[i - k] + siz[i - k] - 1, -1); 52 printf(" %d", seg[1]); 53 } 54 }