set+线段树 Codeforces Round #305 (Div. 2) D. Mike and Feet
1 /*
2 题意:对于长度为x的子序列,每个序列存放为最小值,输出长度为x的子序列的最大值
3 set+线段树:线段树每个结点存放长度为rt的最大值,更新:先升序排序,逐个添加到set中
4 查找左右相邻的位置,更新长度为r - l - 1的最大值,感觉线段树结构体封装不错!
5 详细解释:http://blog.csdn.net/u010660276/article/details/46045777
6 其实还有其他解法,先掌握这种:)
7 */
8 #include <cstdio>
9 #include <algorithm>
10 #include <iostream>
11 #include <iostream>
12 #include <cstring>
13 #include <set>
14 using namespace std;
15
16 typedef long long ll;
17 #define lson l, mid, rt << 1
18 #define rson mid + 1, r, rt << 1 | 1
19
20 const int MAXN = 2e5 + 10;
21 const int INF = 0x3f3f3f3f;
22
23 struct A
24 {
25 int v, id;
26 bool operator < (const A &a) const
27 {
28 return v < a.v;
29 }
30 }a[MAXN];
31 struct SegmentTree
32 {
33 int add[MAXN << 2];
34 int mx[MAXN << 2];
35
36 void push_down(int rt)
37 {
38 if (add[rt])
39 {
40 add[rt<<1] = add[rt<<1|1] = add[rt];
41 mx[rt<<1] = mx[rt<<1|1] = add[rt];
42 add[rt] = 0;
43 }
44 }
45
46 void build(int l, int r, int rt)
47 {
48 add[rt] = mx[rt] = 0;
49 if (l == r) return ;
50 int mid = (l + r) >> 1;
51 build (lson); build (rson);
52 }
53
54 void updata(int ql, int qr, int c, int l, int r, int rt)
55 {
56 if (ql <= l && r <= qr) {mx[rt] = c; add[rt] = c; return ;}
57 push_down (rt);
58 int mid = (l + r) >> 1;
59 if (ql <= mid) updata (ql, qr, c, lson);
60 if (qr > mid) updata (ql, qr, c, rson);
61 }
62
63 int query(int x, int l, int r, int rt)
64 {
65 if (l == r) return mx[rt];
66 push_down (rt);
67 int mid = (l + r) >> 1;
68 if (x <= mid) return query (x, lson);
69 return query (x, rson);
70 }
71 }tree;
72
73 int ans[MAXN];
74
75 int main(void) //Codeforces Round #305 (Div. 2) D. Mike and Feet
76 {
77 int n;
78 while (scanf ("%d", &n) == 1)
79 {
80 for (int i=1; i<=n; ++i)
81 {
82 scanf ("%d", &a[i].v); a[i].id = i;
83 }
84 sort (a+1, a+1+n);
85
86 tree.build (1, n, 1);
87 set<int> S; S.insert (0); S.insert (n + 1);
88 set<int>::iterator it;
89 for (int i=1; i<=n; ++i)
90 {
91 int l, r;
92 it = S.lower_bound (a[i].id);
93 r = *it; it--; l = *it;
94 if (r - l - 1 >= 1) tree.updata (1, r-l-1, a[i].v, 1, n, 1);
95 S.insert (a[i].id);
96 }
97
98 for (int i=1; i<=n; ++i)
99 ans[i] = tree.query (i, 1, n, 1);
100 for (int i=1; i<=n; ++i)
101 printf ("%d%c", ans[i], (i==n) ? '\n' : ' ');
102 }
103
104 return 0;
105 }
106
107 /*
108 10
109 1 2 3 4 5 4 3 2 1 6
110 */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*
2 jinye的解法:原理一样,找到最小值是a[i]的最长区间,用l[],r[]记录左右端点的位置
3 比线段树快多了:)
4 */
5 #include <cstdio>
6 #include <iostream>
7 #include <algorithm>
8 #include <cstring>
9 #include <cmath>
10 using namespace std;
11
12 const int MAXN = 2e5 + 10;
13 const int INF = 0x3f3f3f3f;
14 int a[MAXN], l[MAXN], r[MAXN], ans[MAXN];
15
16 int main(void) //Codeforces Round #305 (Div. 2) D. Mike and Feet
17 {
18 int n;
19 while (scanf ("%d", &n) == 1)
20 {
21 memset (ans, 0, sizeof (ans));
22 for (int i=1; i<=n; ++i)
23 {
24 scanf ("%d", &a[i]);
25 l[i] = r[i] = i;
26 }
27
28 for (int i=1; i<=n; ++i)
29 {
30 while (l[i] > 1 && a[i] <= a[l[i]-1]) l[i] = l[l[i]-1];
31 }
32 for (int i=n; i>=1; --i) //倒过来回超时
33 {
34 while (r[i] < n && a[i] <= a[r[i]+1]) r[i] = r[r[i]+1];
35 }
36
37 for (int i=1; i<=n; ++i)
38 {
39 int x = r[i] - l[i] + 1;
40 ans[x] = max (ans[x], a[i]);
41 }
42
43 for (int i=n-1; i>=1; --i) //可能范围扩展的太厉害了
44 {
45 ans[i] = max (ans[i], ans[i+1]);
46 }
47
48 for (int i=1; i<=n; ++i)
49 printf ("%d%c", ans[i], (i==n) ? '\n' : ' ');
50 }
51
52 return 0;
53 }
编译人生,运行世界!