zoukankan      html  css  js  c++  java
  • CF809D

    好神奇的数据结构呀...

    首先我们考虑:暴力怎么做?

    设状态$dp[j]$表示长度为$j$的序列最后一个数最小是几,如果$j$位置的限制区间为$[l,r]$,那么显然有转移:

    $dp[j]=l(dp[j-1]<l)$

    $dp[j]=dp[j-1]+1(lleq dp[j-1]leq r-1)$

    $dp[j]=dp[j] (dp[j-1] geq r)$

    正确性显然

    考虑优化:我们考虑上面三个操作的实质:

    第一个转移方向:在$l$的前驱后面插入$l$

    第二个转移方向:把区间$[l,r-1]$整体加一,之后右移一格(相当于向后转移了一个位置)

    第三个转移方向:删去$r$的后继

    那么用平衡树直接实现上面三个操作即可,考虑到每次都有插入操作,因此事实上第二个操作不需要真正右移,只需加一即可

    强烈建议fhq_treap实现

    代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <ctime>
    #define ls tree[rt].lson
    #define rs tree[rt].rson
    using namespace std;
    struct FHQ_TREAP
    {
        int lson,rson;
        int siz;
        int val,rank;
        int lazy;
    }tree[300005];
    int tot=0;
    int rot,re,n;
    void pushup(int rt)
    {
        tree[rt].siz=tree[ls].siz+tree[rs].siz+1;
    }
    void pushdown(int rt)
    {
        if(!rt)return;
        if(ls)tree[ls].lazy+=tree[rt].lazy,tree[ls].val+=tree[rt].lazy;
        if(rs)tree[rs].val+=tree[rt].lazy,tree[rs].lazy+=tree[rt].lazy;
        tree[rt].lazy=0;
    }
    int new_node(int v)
    {
        int ret=++tot;
        tree[ret].siz=1,tree[ret].val=v,tree[ret].rank=rand();
        return ret;
    }
    int merge(int x,int y)
    {
        if((!x)||(!y))return x|y;
        if(tree[x].lazy)pushdown(x);
        if(tree[y].lazy)pushdown(y);
        if(tree[x].rank<tree[y].rank)
        {
            tree[x].rson=merge(tree[x].rson,y);
            pushup(x);
            return x;
        }else
        {
            tree[y].lson=merge(x,tree[y].lson);
            pushup(y);
            return y;
        }
    }
    void split(int rt,int k,int &x,int &y)
    {
        if(!rt){x=y=0;return;}
        if(tree[rt].lazy)pushdown(rt);
        if(tree[rt].val<=k)x=rt,split(rs,k,rs,y);
        else y=rt,split(ls,k,x,ls);
        pushup(rt);
    }
    void ins(int v)
    {
        int x,y;
        split(rot,v,x,y);
        rot=merge(merge(x,new_node(v)),y);
    }
    void del(int v)
    {
        int x,y,z,w;
        split(rot,v,x,y);
        split(x,v-1,z,w);
        w=merge(tree[w].lson,tree[w].rson);
        rot=merge(merge(z,w),y);
    }
    void update(int rt,int l,int r)
    {
        int x,y,z,w;
        split(rot,l-1,x,y);
        split(y,r,z,w);
        if(z)tree[z].lazy++,tree[z].val++;
        rot=merge(x,merge(z,w));
    }
    void get_pro(int rt,int v)
    {
        if(!rt)return;
        if(v<=tree[rt].val)get_pro(ls,v);
        else re=tree[rt].val,get_pro(rs,v);
    }
    int get_minn(int rt)
    {
        if(!ls)return tree[rt].val;
        else return get_minn(ls);
    }
    int get_sub(int v)
    {
        int x,y;
        split(rot,v,x,y);
        int ret=get_minn(y);
        rot=merge(x,y);
        return ret;
    }
    inline int read()
    {
        int f=1,x=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void solve()
    {
        srand(time(NULL));
        n=read();
        for(int i=1;i<=n;i++)
        {
            int l=read(),r=read();
            if(i==1){ins(l);continue;}
            re=get_sub(r-1);
            update(rot,l,r-1);
            if(re)del(re);
            ins(l);
        }
        if(!rot)printf("0
    ");
        else printf("%d
    ",tree[rot].siz);
    }
    int main()
    {
        solve();
        return 0;
    }
  • 相关阅读:
    ToDesk 远程连接软件 连接远程电脑后黑屏
    Kentico updateall
    Stylesheet not loaded because of MIME-type
    Linux tail 命令作用及其常用用法
    浅析Linux中stty命令的作用、常用用法及案例使用
    【MySQL】修改表的存储引擎
    【MySQL】查看MySQL的默认存储引擎(Win环境)
    【Swing/STS】在Spring Tool Suite中制作可执行jar
    [Swing]我的作品 图片幻灯式浏览软件PicturesShow 献给广大美图爱好者的福音
    【Java Swing】如何给Jframe添加键盘和鼠标事件处理
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11101131.html
Copyright © 2011-2022 走看看