• [BZOJ3173]最长上升子序列


    Problem

    给你n个数A1~An,每次将i插入第Ai位后,最后输出每次插入后这个数列的最长上升子序列

    Solution

    这道题非常的妙。首先如果新加入的这个数构成了最长上升子序列,由于在它插入之前都是比它小的数,所以就是最后这个序列这个位置的最长上升子序列。
    如果不是最长的,只需要和前面那个数插入构成的最长上升子序列长度取max。
    构造最后的序列长度可以用Treap维护。

    Notice

    插入点时,不用记录是第几个数,因为Treap新建节点的顺序就是插入的顺序。

    Code

    非旋转Treap

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define sqz main
    #define ll long long
    #define reg register int
    #define rep(i, a, b) for (reg i = a; i <= b; i++)
    #define per(i, a, b) for (reg i = a; i >= b; i--)
    #define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
    const int INF = 1e9, N = 100000;
    const double eps = 1e-6, phi = acos(-1.0);
    ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
    ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
    void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
    int point = 0, root, f[N + 5], g[N + 5], T[N + 5], now = 0;
    struct node
    {
    	int Val[N + 5], Level[N + 5], Size[N + 5], Son[2][N + 5];
    	inline void up(int u)
        {
            Size[u] = Size[Son[0][u]] + Size[Son[1][u]] + 1;
        }
        int Newnode(int v)
        {
            int u = ++point;
            Val[u] = v, Level[u] = rand();
            Son[0][u] = Son[1][u] = 0, Size[u] = 1;
            return u;
        }
        int Merge(int X, int Y)
        {
            if (X * Y == 0) return X + Y;
            if (Level[X] < Level[Y])
            {
                Son[1][X] = Merge(Son[1][X], Y);
                up(X); return X;
            }
            else
            {
                Son[0][Y] = Merge(X, Son[0][Y]);
                up(Y); return Y;
            }
        }
        void Split(int u, int t, int &x, int &y)
        {
            if (!u)
    		{
    			x = y = 0;
    			return;
    		}
            if (Size[Son[0][u]] < t) x = u, Split(Son[1][u], t - Size[Son[0][u]] - 1, Son[1][u], y);
            else y = u, Split(Son[0][u], t, x, Son[0][u]);
            up(u);
        }
        void Build(int l, int r)
        {
            int last, u, s[N + 5], top = 0;
            rep(i, l, r)
            {
                int u = Newnode(T[i]);
                last = 0;
                while (top && Level[s[top]] > Level[u])
                {
                    up(s[top]);
                    last = s[top];
                    s[top--] = 0;
                }
                if (top) Son[1][s[top]] = u;
                Son[0][u] = last;
                s[++top] = u;
            }
            while (top) up(s[top--]);
            root = s[1];
        }
        int Find_rank(int v)
        {
            int x, y, t;
        	Split(root, v - 1, x, y);
        	t = Size[x];
        	root = Merge(x, y);
        	return t + 1;
        }
        int Find_num(int u, int v)
        {
            if (!u) return 0;
            if (v <= Size[Son[0][u]]) return Find_num(Son[0][u], v);
            else if (v <= Size[Son[0][u]] + 1) return u;
            else return Find_num(Son[1][u], v - Size[Son[0][u]] - 1);
        }
        void Insert(int v)
        {
        	int t = Newnode(v), x, y;
            Split(root, v, x, y);
        	root = Merge(Merge(x, t), y);
        }
    	void Out(int u)
    	{
    	    if (!u) return;
    	    Out(Son[0][u]);
    	    T[++now] = u;
    	    Out(Son[1][u]);
    	}
    }Treap;
    
    int sqz()
    {
        int n = read();
        rep(i, 1, n)
        {
            int x = read();
            Treap.Insert(x);
        }
        Treap.Out(root);
        g[0] = -1, f[0] = 1;
        int len = 0;
        rep(i, 1, n)
        {
            int t = lower_bound(g, g + len + 1, T[i]) - g;
            f[T[i]] = t;
            if (t == len + 1) g[++len] = T[i];
            else g[t] = T[i];
        }
        rep(i, 1, n)
        {
            f[i] = max(f[i - 1], f[i]);
            printf("%d
    ", f[i]);
        }
        return 0;
    }
    

    旋转Treap

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define sqz main
    #define ll long long
    #define reg register int
    #define rep(i, a, b) for (reg i = a; i <= b; i++)
    #define per(i, a, b) for (reg i = a; i >= b; i--)
    #define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
    const int INF = 1e9, N = 100000;
    const double eps = 1e-6, phi = acos(-1.0);
    ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
    ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
    void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
    int point = 0, root, f[N + 5], g[N + 5], T[N + 5], now = 0;
    struct node
    {
    	int Val[N + 5], Level[N + 5], Size[N + 5], Son[2][N + 5];
    	inline void up(int u)
    	{
    		Size[u] = Size[Son[0][u]] + Size[Son[1][u]] + 1;
    	}
    	inline void Newnode(int &u, int v)
    	{
    		u = ++point;
    		Level[u] = rand(), Val[u] = v;
    		Size[u] = 1, Son[0][u] = Son[1][u] = 0;
    	}
    	inline void Lturn(int &x)
    	{
    		int y = Son[1][x]; Son[1][x] = Son[0][y], Son[0][y] = x;
    		Size[y] = Size[x]; up(x); x = y;
    	}
    	inline void Rturn(int &x)
    	{
    		int y = Son[0][x]; Son[0][x] = Son[1][y], Son[1][y] = x;
    		Size[y] = Size[x]; up(x); x = y;
    	}
    
    	void Insert(int &u, int t)
    	{
    		if (u == 0)
    		{
    			Newnode(u, t);
    			return;
    		}
    		Size[u]++;
    		if (Size[Son[0][u]] >= t)
    		{
    			Insert(Son[0][u], t);
    			if (Level[Son[0][u]] < Level[u]) Rturn(u);
    		}
    		else
    		{
    			Insert(Son[1][u], t - Size[Son[0][u]] - 1);
    			if (Level[Son[1][u]] < Level[u]) Lturn(u);
    		}
    	}
    	int Find_num(int u, int t)
    	{
    		if (!u) return 0;
    		if (t <= Size[Son[0][u]]) return Find_num(Son[0][u], t);
    		else if (t <= Size[Son[0][u]] + 1) return Val[u];
    		else return Find_num(Son[1][u], t - Size[Son[0][u]] - 1);
    	}
    	void Out(int u)
    	{
    	    if (!u) return;
    	    Out(Son[0][u]);
    	    T[++now] = u;
    	    Out(Son[1][u]);
    	}
    }Treap;
    
    int sqz()
    {
        int n = read();
        rep(i, 1, n)
        {
            int x = read();
            Treap.Insert(root, x);
        }
        Treap.Out(root);
        g[0] = -1, f[0] = 1;
        int len = 0;
        rep(i, 1, n)
        {
            int t = lower_bound(g, g + len + 1, T[i]) - g;
            f[T[i]] = t;
            if (t == len + 1) g[++len] = T[i];
            else g[t] = T[i];
        }
        rep(i, 1, n)
        {
            f[i] = max(f[i - 1], f[i]);
            printf("%d
    ", f[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    现代软件工程 第一章 概论 第4题——邓琨
    现代软件工程 第一章 概论 第9题——邓琨
    现代软件工程 第一章 概论 第7题——张星星
    现代软件工程 第一章 概论 第5题——韩婧
    hdu 5821 Ball 贪心(多校)
    hdu 1074 Doing Homework 状压dp
    hdu 1074 Doing Homework 状压dp
    hdu 1069 Monkey and Banana LIS变形
    最长上升子序列的初步学习
    hdu 1024 Max Sum Plus Plus(m段最大子列和)
  • 原文地址:https://www.cnblogs.com/WizardCowboy/p/7643634.html
Copyright © 2020-2023  润新知