zoukankan      html  css  js  c++  java
  • bzoj 3173 [Tjoi2013]最长上升子序列 (treap模拟+lis)

     [Tjoi2013]最长上升子序列

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 2213  Solved: 1119
    [Submit][Status][Discuss]

    Description

    给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

    Input

    第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

    Output

    N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

    Sample Input

    3
    0 0 2

    Sample Output

    1
    1
    2

    HINT

    100%的数据 n<=100000

    Source

    题解

        这道题目因为是顺序插入,求的是最长上升子序列,所以不改变当前位置的

        最长上升序列长度。

        放一个大的数在前面不影响,在中间,不影响,在后面,当当前位置为止的话也还是不影响的。

        所以只需要模拟出最后序列即可,怎么模拟,是关键。

        我是用平衡树维护的。

        点的编号即为当前插入点。

        最后求一次LIS即可。

      1 #include<cstring>
      2 #include<cmath>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cstdio>
      6 
      7 #define ls tr[p].l
      8 #define rs tr[p].r
      9 #define N 100007
     10 #define inf 1000000007
     11 using namespace std;
     12 inline int read()
     13 {
     14     int x=0,f=1;char ch=getchar();
     15     while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
     16     while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
     17     return x*f;
     18 }
     19 
     20 int n,m,sz,rt,bh,top,now;
     21 char flag[3];
     22 int f[N],v[N],ans[N];
     23 struct Node
     24 {
     25     int l,r,val,siz,rnd;
     26 }tr[N];
     27 
     28 inline int rand()
     29 {
     30     static int seed=2333;
     31     return seed=(int)((((seed^998244353)+19260817ll)*19890604ll)%1000000007);
     32 }
     33 
     34 inline void update(int p)
     35 {
     36     tr[p].siz=tr[ls].siz+tr[rs].siz+1;
     37 }
     38 void lturn(int &p)
     39 {
     40     int t=tr[p].r;tr[p].r=tr[t].l;tr[t].l=p;
     41     tr[t].siz=tr[p].siz;update(p);p=t;
     42 }
     43 void rturn(int &p)
     44 {
     45     int t=tr[p].l;tr[p].l=tr[t].r;tr[t].r=p;
     46     tr[t].siz=tr[p].siz;update(p);p=t;
     47 }
     48 void ins(int &p,int x)
     49 {
     50     if (p==0)
     51     {
     52         p=++sz;
     53         tr[p].siz=1,tr[p].rnd=rand();
     54         return;
     55     }
     56     tr[p].siz++;
     57     if (tr[ls].siz<x)
     58     {
     59         ins(rs,x-tr[ls].siz-1);
     60         if (tr[rs].rnd<tr[p].rnd) lturn(p);
     61     }
     62     else
     63     {
     64         ins(ls,x);
     65         if (tr[ls].rnd<tr[p].rnd) rturn(p);
     66     }
     67 }
     68 void dfs(int p)
     69 {
     70     if (!p) return;
     71     dfs(ls);
     72     v[++now]=p;
     73     dfs(rs);
     74 }
     75 void solve()
     76 {
     77     memset(f,127,sizeof(f)),f[0]=-inf;
     78     for (int i=1;i<=n;i++)
     79     {
     80         int t=upper_bound(f,f+top+1,v[i])-f;
     81         if (f[t-1]<=v[i])
     82         {
     83             f[t]=min(f[t],v[i]);
     84             ans[v[i]]=t;
     85             top=max(t,top);
     86         }
     87     }
     88 }
     89 int main()
     90 {
     91     n=read();
     92     for (int i=1;i<=n;i++)
     93     {
     94         int x=read();now=i;
     95         ins(rt,x);
     96     }
     97     now=0,dfs(rt);
     98     solve();
     99     for (int i=1;i<=n;i++)
    100     {
    101         ans[i]=max(ans[i-1],ans[i]);
    102         printf("%d
    ",ans[i]);
    103     }
    104 }
  • 相关阅读:
    效率分页代码
    serialPort控件(串口通信)
    C#事件DEMO
    泛型类
    简单的登陆页面
    hdu 1342+hdu 2660+hdu 2266+hdu 1704+hdu 1627+hdu 1539
    hdu 3987(求割边最小的最小割)
    hdu 1907(尼姆博弈)
    hdu 2149+hdu 1846(巴什博弈)
    hdu 2516(斐波那契博弈)
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8005062.html
Copyright © 2011-2022 走看看