小R的树(权限题)

解:考场上爆0了......

回想怎么求两个排列的最长公共子序列。

回想怎么求1~n每个数恰出现两次的两个序列的最长公共子序列。就是每个数替换为它在另一个序列里的出现位置,降序。

所以我们可以把这每个空位都倒序填入m个数,然后暴力,最后输出方案。

考虑优化。发现在每个空位的时候,这m个数都是单降的。直接拿指针在单调栈上扫,可以O(top + m)转移。

关于记录方案,每个位置记录以它结尾的lis中的前一个非-1位置,以及在这之间有多少个-1。

然后就可以把空间优化到O(n)。

 1 #include <bits/stdc++.h>
 2 
 3 typedef long long LL;
 4 const int N = 200010;
 5 const LL INF = 0x3f3f3f3f3f3f3f3fll;;
 6 
 7 struct Node {
 8     int a, b;
 9     Node(int A = 0, int B = 0) {
10         a = A;
11         b = B;
12     }
13 }frp[N], fr[N];
14 
15 LL a[N], b[N], p[N];
16 int top, n, m;
17 bool vis[N];
18 
19 int main() {
20     scanf("%d", &n);
21     for(int i = 1; i <= n; i++) {
22         scanf("%lld", &a[i]);
23     }
24     scanf("%d", &m);
25     for(int i = 1; i <= m; i++) {
26         scanf("%lld", &b[i]);
27     }
28     std::sort(b + 1, b + m + 1);
29     std::reverse(b + 1, b + m + 1);
30     a[n + 1] = INF;
31     for(int i = 1; i <= n + 1; i++) {
32         if(a[i] != -1) {
33             int l = 0, r = top;
34             while(l < r) {
35                 int mid = (l + r + 1) >> 1;
36                 if(p[mid] < a[i]) l = mid;
37                 else r = mid - 1;
38             }
39             fr[i] = frp[r];
40             if(r == top) {
41                 p[++top] = a[i];
42                 frp[top] = Node(i, 0);
43             }
44             else if(p[r + 1] > a[i]) {
45                 p[r + 1] = a[i];
46                 frp[r + 1] = Node(i, 0);
47             }
48         }
49         else {
50             int p1 = top;
51             for(int j = 1; j <= m; j++) {
52                 while(p1 && p[p1] >= b[j]) {
53                     p1--;
54                 }
55                 Node temp = frp[p1];
56                 temp.b++;
57                 if(p1 == top) {
58                     p[++top] = b[j];
59                     frp[top] = temp;
60                 }
61                 else if(p[p1 + 1] > b[j]) {
62                     p[p1 + 1] = b[j];
63                     frp[p1 + 1] = temp;
64                 }
65             }
66         }
67     }
68 
69     int now = frp[top].a, p1 = n, p2 = 1;
70     while(now) {
71         if(fr[now].b) {
72             while(p1 > now) p1--;
73             while(b[p2] >= a[now]) p2++;
74             for(int i = 1; i <= fr[now].b; i++) {
75                 while(a[p1] != -1) p1--;
76                 a[p1] = b[p2];
77                 vis[p2] = 1;
78                 p2++;
79             }
80         }
81         now = fr[now].a;
82     }
83 
84     p2 = 1;
85     for(int i = 1; i <= n; i++) {
86         if(a[i] == -1) {
87             while(vis[p2]) p2++;
88             a[i] = b[p2];
89             p2++;
90         }
91     }
92 
93     for(int i = 1; i <= n; i++) {
94         printf("%lld ", a[i]);
95     }
96     return 0;
97 }
AC代码

 

posted @ 2019-03-24 18:00  huyufeifei  阅读(136)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜