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 */

 

 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 }
数组效率更高

 

你可能感兴趣的:(codeforces)