zoukankan      html  css  js  c++  java
  • BZOJ 3173 [Tjoi2013] 最长上升子序列 解题报告

    这个题感觉比较简单,但却比较容易想残。。

    我不会用树状数组求这个原排列,于是我只好用线段树。。。毕竟 Gromah 果弱马。

    我们可以直接依次求出原排列的元素,每次找到最小并且最靠右的那个元素,假设这是第 $i$ 次找的,那么这就是原排列的第 $i$ 项,然后我们就把这个元素删去(变成很大的数),再把这个数以左的数都加 1,进行下一轮。

    然后就是裸的最长上升子序列啦~~~

    时间复杂度 $O(nlog n)$,空间复杂度 $O(n)$。

      1 #include <cstdio>
      2 #include <algorithm>
      3 using namespace std;
      4 #define N 100000 + 5
      5 #define M 262144 + 5
      6 #define ls(x) x << 1
      7 #define rs(x) x << 1 | 1
      8  
      9 int n, Pos[N], A[N], T[N], F[N];
     10  
     11 struct Segment_Tree
     12 {
     13     int Min, delta;
     14 }h[M];
     15  
     16 inline void Build(int x, int l, int r)
     17 {
     18     if (l == r)
     19     {
     20         h[x].Min = Pos[l];
     21         return ;
     22     }
     23     int mid = l + r >> 1;
     24     Build(ls(x), l, mid);
     25     Build(rs(x), mid + 1, r);
     26     h[x].Min = min(h[ls(x)].Min, h[rs(x)].Min);
     27 }
     28  
     29 inline void apply(int x, int d)
     30 {
     31     h[x].Min += d, h[x].delta += d;
     32 }
     33  
     34 inline void push(int x)
     35 {
     36     if (h[x].delta)
     37     {
     38         apply(ls(x), h[x].delta);
     39         apply(rs(x), h[x].delta);
     40         h[x].delta = 0;
     41     }
     42 }
     43  
     44 inline void Modify(int x, int l, int r, int s, int t, int d)
     45 {
     46     if (l == s && r == t)
     47     {
     48         apply(x, d);
     49         return ;
     50     }
     51     push(x);
     52     int mid = l + r >> 1;
     53     if (t <= mid) Modify(ls(x), l, mid, s, t, d);
     54         else if (s > mid) Modify(rs(x), mid + 1, r, s, t, d);
     55         else Modify(ls(x), l, mid, s, mid, d), Modify(rs(x), mid + 1, r, mid + 1, t, d);
     56     h[x].Min = min(h[ls(x)].Min, h[rs(x)].Min);
     57 }
     58  
     59 inline int Query(int x, int l, int r)
     60 {
     61     if (l == r) return l;
     62     int mid = l + r >> 1;
     63     if (h[rs(x)].Min <= h[ls(x)].Min)
     64         return Query(rs(x), mid + 1, r);
     65     else return Query(ls(x), l, mid);
     66 }
     67  
     68 int main()
     69 {
     70     #ifndef ONLINE_JUDGE
     71         freopen("3173.in", "r", stdin);
     72         freopen("3173.out", "w", stdout);
     73     #endif
     74      
     75     scanf("%d", &n);
     76     for (int i = 1; i <= n; i ++)
     77         scanf("%d", Pos + i);
     78     Build(1, 1, n);
     79     for (int i = 1; i <= n; i ++)
     80     {
     81         int t = Query(1, 1, n);
     82         Modify(1, 1, n, 1, t, 1);
     83         Modify(1, 1, n, t, t, n);
     84         if (!T[0] || T[T[0]] < t)
     85         {
     86             T[++ T[0]] = t;
     87             F[t] = T[0];
     88         }
     89         else
     90         {
     91             int x = lower_bound(T + 1, T + T[0] + 1, t) - T;
     92             T[x] = t;
     93             F[t] = x;
     94         }
     95     }
     96     for (int i = 1, Max = 0; i <= n; i ++)
     97     {
     98         Max = Max > F[i] ? Max : F[i];
     99         printf("%d
    ", Max);
    100     }
    101      
    102     #ifndef ONLINE_JUDGE
    103         fclose(stdin);
    104         fclose(stdout);
    105     #endif
    106     return 0;
    107 }
    3173_Gromah
  • 相关阅读:
    Linux安装Docker
    Api接口防攻击防刷注解实现
    Api接口鉴权注解实现
    RSA加解密 Java
    Windows安装Mysql 5.7
    Mysql创建自增序列
    new String与toString的区别
    各排序算法复杂度及稳定性
    描述快排以及其复杂度
    innodb和myisam的区别
  • 原文地址:https://www.cnblogs.com/gromah/p/4601012.html
Copyright © 2011-2022 走看看