传送门


看到最长上升子序列肯定是DP

设\(f_i\)表示计算到当前,长度为\(i\)的最长上升子序列的最后一项的最小值,显然\(f_i\)是一个单调递增的序列。

转移:对于当前计算的元素\(x\),它的取值范围为\([l,r]\),设当前可以转移的区间为\([j,k]\)(即对于\(\forall p \in [j,k] , f_p \in [l,r)\)且\(f_{j-1} < l , f_{k + 1} \geq r\)),则对于\(\forall p \in [j,k]\)都有\(f_{p + 1} = f_{p} + 1\)(因为序列\(f_i\)是单调递增的,所以转移一定更优)且\(f_j = l\)。

考虑这个转移方程,它的实质就是:删去第\(k+1\)个元素,第\(j\)到\(k\)个元素统一\(+1\),在第\(j\)个元素的左边插入一个值为\(l\)的元素。其实就是平衡树的基本操作,使用平衡树维护即可。

还有我也不知道我的Splay为什么每一次要随机一个点Splay到根才能过……

#include<bits/stdc++.h>
#define MAXN 300010
#define inf 0x7fffffff
using namespace std;

struct node{
    int ch[2] , fa , num , add;
}Tree[MAXN];
int cntNode = 2 , N , root = 1;

inline bool son(int dir){
    return Tree[Tree[dir].fa].ch[1] == dir;
}

inline void ZigZag(int dir){
    bool f = son(dir);
    if(Tree[dir].fa == root)
        root = dir;
    Tree[Tree[dir].fa].ch[f] = Tree[dir].ch[f ^ 1];
    Tree[Tree[dir].ch[f ^ 1]].fa = Tree[dir].fa;
    int x = Tree[Tree[dir].fa].fa;
    Tree[x].ch[son(Tree[dir].fa)] = dir;
    Tree[Tree[dir].fa].fa = dir;
    Tree[dir].ch[f ^ 1] = Tree[dir].fa;
    Tree[dir].fa = x;
}

inline void pushdown(int dir){
    if(Tree[dir].add){
        Tree[Tree[dir].ch[0]].add += Tree[dir].add;
        Tree[Tree[dir].ch[1]].add += Tree[dir].add;
        Tree[Tree[dir].ch[0]].num += Tree[dir].add;
        Tree[Tree[dir].ch[1]].num += Tree[dir].add;
        Tree[dir].add = 0;
    }
}

inline void Splay(int dir , int fa){
    pushdown(dir);
    while(Tree[dir].fa != fa)
        if(Tree[Tree[dir].fa].fa == fa)
            ZigZag(dir);
        else{
            if(son(Tree[dir].fa) == son(dir))
                ZigZag(Tree[dir].fa);
            else
                ZigZag(dir);
            ZigZag(dir);
        }
}

void insert(int &now , int num , int fa){
    if(now == 0){
        now = ++cntNode;
        Tree[now].num = num;
        Tree[now].fa = fa;
        Splay(now , 0);
        return;
    }
    pushdown(now);
    insert(Tree[now].ch[Tree[now].num < num] , num , now);
}

void getPre(int now , int num , int minN){
    if(now == 0){
        Splay(minN , 0);
        return;
    }
    pushdown(now);
    if(Tree[now].num == num){
        int t = Tree[now].ch[0];
        while(t){
            pushdown(t);
            if(Tree[t].num != num)
                minN = t;
            t = Tree[t].ch[1];
        }
        Splay(minN , 0);
        return;
    }
    if(Tree[now].num < num)
        getPre(Tree[now].ch[1] , num , Tree[now].num > Tree[minN].num ? now : minN);
    else
        getPre(Tree[now].ch[0] , num , minN);
}

void getNXT(int now , int num , int maxN){
    if(now == 0){
        Splay(maxN , root);
        return;
    }
    pushdown(now);
    if(Tree[now].num == num){
        int t = Tree[now].ch[1];
        while(t){
            pushdown(t);
            maxN = t;
            t = Tree[t].ch[0];
        }
        Splay(maxN , root);
        return;
    }
    if(Tree[now].num < num)
        getNXT(Tree[now].ch[1] , num , maxN);
    else
        getNXT(Tree[now].ch[0] , num , Tree[now].num < Tree[maxN].num ? now : maxN);
}

inline void find(int dir){
    if(Tree[dir].fa)
        find(Tree[dir].fa);
    pushdown(dir);
}

int main(){
    srand((unsigned)time(0));
    int ans = 0;
    scanf("%d" , &N);
    Tree[1].ch[1] = 2;
    Tree[2].num = inf;
    Tree[2].fa = 1;
    for(int i = 1 ; i <= N ; i++){
        int a , b;
        scanf("%d%d" , &a , &b);
        getPre(root , a , 1);
        getNXT(root , b - 1 , 2);
        Tree[Tree[Tree[root].ch[1]].ch[0]].add++;
        Tree[Tree[Tree[root].ch[1]].ch[0]].num++;
        if(Tree[Tree[root].ch[1]].ch[1]){
            ZigZag(Tree[root].ch[1]);
            getNXT(Tree[root].ch[1] , Tree[root].num , 2);
            Tree[Tree[root].ch[1]].ch[0] = Tree[root].ch[0];
            root = Tree[root].ch[1];
            Tree[Tree[root].ch[0]].fa = root;
            Tree[root].fa = 0;
        }
        else
            ans++;
        insert(Tree[root].ch[Tree[root].num < a] , a , root);
        int t = rand() % (i + 2) + 1;
        find(t);
        Splay(t , 0);
    }
    cout << ans;
    return 0;
}

CF809D Hitchhiking in the Baltic States LIS、平衡树的更多相关文章

  1. CF809D Hitchhiking in the Baltic States

    CF809D Hitchhiking in the Baltic States CF809D 长度为n的序列{xi},n<=3e5,范围在(li,ri)之间,求LIS最长是多长g(i,l)表示前 ...

  2. 【CF809D】Hitchhiking in the Baltic States Splay

    [CF809D]Hitchhiking in the Baltic States 题意:给你n个区间[li,ri],让你选出从中一个子序列,然后在子序列的每个区间里都选择一个tj,满足$t_1< ...

  3. 【CF809D】Hitchhiking in the Baltic States(Splay,动态规划)

    [CF809D]Hitchhiking in the Baltic States(Splay,动态规划) 题面 CF 洛谷 题解 朴素\(dp\):设\(f[i][j]\)表示当前考虑到第\(i\)个 ...

  4. 【CF809D】Hitchhiking in the Baltic States

    题意: 给你n个区间[li,ri],让你选出从中一个子序列,然后在子序列的每个区间里都选择一个tj,满足t1<t2<...<tlent1<t2<...<tlen.最 ...

  5. CF 809 D Hitchhiking in the Baltic States —— 思路+DP(LIS)+splay优化

    题目:http://codeforces.com/contest/809/problem/D 看题解,抄标程...发现自己连 splay 都快不会写了... 首先,题目就是要得到一个 LIS: 但与一 ...

  6. Codeforces 809D. Hitchhiking in the Baltic States

    Description 给出 \(n\) 个数 \(a_i\),每一个数有一个取值 \([l_i,r_i]\) ,你来确定每一个数,使得 \(LIS\) 最大 题面 Solution 按照平时做法,设 ...

  7. CodeForces 809D Hitchhiking in the Baltic States(FHQ-Treap)

    题意 给你长度为$n$的序列,序列中的每个元素$i$有一个区间限制$[l_i,r_i]$,你从中选出一个子序列,并给它们标号$x_i$,要求满足 $,∀i<j,x_i<x_j$,且$, ∀ ...

  8. CF 809D Hitchhiking in the Baltic States——splay+dp

    题目:http://codeforces.com/contest/809/problem/D 如果值是固定的,新加入一个值,可以让第一个值大于它的那个长度的值等于它. 如今值是一段区间,就对区间内的d ...

  9. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

随机推荐

  1. LearnX控件漏洞挖掘与利用

    前言 大学英语会用到一个 ActiveX 插件 LearnX ,最近从网上下了一个下来分析了一下,找到了一些漏洞并完成了 exploit . 虽然涉及的知识比较老旧,不过还是挺有意思的.这里分享一下整 ...

  2. git批量修改已经提交的commit的姓名和邮箱

    首先,我们创建change.sh脚本,并根据个人信息复制以下脚本. #!/bin/sh git filter-branch --env-filter ' OLD_EMAIL="填写原来的邮箱 ...

  3. AJAX的优点 个人理解记录

    1:对网站性能的提高.例如我只需要刷新页面中购物车的数据,使用ajax时不需要请求整个页面的数据,对于客户端和服务器的压力都会降低, 减少了ISP的负担,服务器的空间和带宽压力都会降低. 2:用户体验 ...

  4. Django之form总结

    复习Django项目结构: 主要的文件:manage.py,url.py,views.py,settings.py,models.py manage.py:项目管理文件,一般不做修改. url.py: ...

  5. [20171120]理解v$session的state字段(11G).txt

    [20171120]理解v$session的state字段(11G).txt --//https://blogs.oracle.com/database4cn/vsession-%e4%bd%a0%e ...

  6. char/varchar/nvarchar的区别

    原文:https://blog.csdn.net/w516162189/article/details/78914035 我们在设计数据库的时候,需要根据需求场景选择合适的字段类型,对数据的执行效率有 ...

  7. 数据层的多租户浅谈(SAAS多租户数据库设计)

    在上一篇“浅析多租户在 Java 平台和某些 PaaS 上的实现”中我们谈到了应用层面的多租户架构,涉及到 PaaS.JVM.OS 等,与之相应的是数据层也有多租户的支持. 数据层的多租户综述 多租户 ...

  8. 【hexo】03config文件配置详解

    YAML 是专门用来写配置文件的语言,非常简洁和强大,我们的配置文件就是这种格式.需要了解的只有: # 我是文配置件的注释 重要提示,例如:"theme: landspace"中冒 ...

  9. 从列表和实例来了解python迭代器

    什么是迭代器?它是一个带状态的对象,在你调用next()方法的时候返回容器中的下一个值,任何实现了__iter__和__next__()(python2中实现next())方法的对象都是迭代器,__i ...

  10. system函数的应用

    system函数的两个简单应用 1.调用cmd命令.例:(打开计算器) #include <stdlib.h> int main() { system("calc"); ...