CF1132G Greedy Subsequences

题目链接:洛谷

题目大意:对于一个长度为$n$的序列$a_i$,它的最长贪心严格上升子序列定义为(1)最长上升子序列(2)对于这个子序列,每个数的后继必须是在原序列中它右边第一个比它大的数。求所有长度为$k$的子区间中,它的最长贪心严格上升子序列的长度。

数据范围:$1\leq k\leq n\leq 10^6,1\leq a_i\leq 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/AThousandMoons/p/10624072.html