CF809D Hitchhiking in the Baltic States

题目描述:

luogu

题解:

平衡树模拟dp?

设$dp[i]$表示当前状态下长为$i$的合法子序列最后一位的最小值。

容易发现$dp[i]<dp[i+1]$。

然后就可以$dp$了。

(当前可操作区间为$[l,r]$)

1.$dp[i-1]<l$,有$dp[i]=min(dp[i],l)$。

此时满足$dp[i-1]<l \le dp[i]$。

2.$l \le dp[i-1] < r$,有$dp[i]=min(dp[i],dp[i-1]+1)$,

其实右边一定最右,因为$dp[i-1]<dp[i]$。

3.$dp[i-1] \ge r$,此时$dp[i]=dp[i]$。

我们可以用平衡树维护这个转移。

对于转移1,我们要插入一个$l$。

对于转移2,我们要将一段区间平移后+1。

所以,用splay维护插入、区间加法和删除。

注意三者顺序。

(splay双旋写成反双旋卡在第80个点卡了半天

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int inf = 0x7f7f7f7f;
const int N = 500050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n;
struct Splay
{
    int tot,rt,ch[N][2],fa[N],siz[N];
    int w[N],tag[N];
    Splay()
    {
        tot = 2;rt = 1;
        w[1] = -inf,w[2] = inf;
        fa[2] = 1,ch[1][1] = 2;
        siz[1] = 2,siz[2] = 1;
    }
    void update(int u){siz[u]=siz[ch[u][0]]+siz[ch[u][1]]+1;}
    void add(int u,int k){if(u)w[u]+=k,tag[u]+=k;}
    void pushdown(int u)
    {
        if(tag[u])
        {
            add(ch[u][0],tag[u]);
            add(ch[u][1],tag[u]);
            tag[u]=0;
        }
    }
    int now;
    void rotate(int x)
    {
        int y = fa[x],z = fa[y],k = (ch[y][1]==x);
        ch[z][ch[z][1]==y]=x,fa[x]=z;
        ch[y][k]=ch[x][!k],fa[ch[x][!k]]=y;
        ch[x][!k]=y,fa[y]=x;
        update(y),update(x);
    }
    int sta[N],tl;
    void down(int x)
    {
        sta[tl=1]=x;
        while(fa[x])x=fa[x],sta[++tl]=x;
        while(tl)pushdown(sta[tl--]);
    }
    void splay(int x,int goal)
    {
        down(x);
        while(fa[x]!=goal)
        {
            int y = fa[x],z = fa[y];
            if(z!=goal)
                (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
            rotate(x);
        }
        if(!goal)rt=x;
    }
    void get_qq(int u,int k)
    {
        if(!u)return ;pushdown(u);
        if(w[u]<=k)now=u,get_qq(ch[u][1],k);
        else get_qq(ch[u][0],k);
    }
    void get_hj(int u,int k)
    {
        if(!u)return ;pushdown(u);
        if(w[u]>=k)now=u,get_hj(ch[u][0],k);
        else get_hj(ch[u][1],k);
    }
    int qq(int k){get_qq(rt,k);splay(now,0);return now;}
    int hj(int k){get_hj(rt,k);splay(now,0);return now;}
    void work(int l,int r)
    {
        int lp,rp,u;
        
        lp = hj(r);
        if(lp!=2)
        {
            rp = hj(w[lp]+1),lp = qq(w[lp]-1);
            splay(lp,0),splay(rp,lp);
            ch[rp][0]=0;
            update(rp),update(lp);
        }

//        u = qq(inf-1);
//        splay(u,0);

        lp = qq(l-1),rp = hj(r);
        splay(lp,0),splay(rp,lp);
        add(ch[rp][0],1);

//        u = qq(inf-1);
//        splay(u,0);

        rp = hj(w[lp]+1);
        splay(lp,0),splay(rp,lp);
        u = ++tot;w[u]=l;
        siz[u] = 1,fa[u] = rp,ch[rp][0] = u;
        update(rp),update(lp);
//        splay(u,0);
        
//        int mid = (2int*l+3int*r)/5;
        u = qq(inf-1);
        splay(u,0);
    }
}tr;
int main()
{
//    freopen("tt.in","r",stdin);
    read(n);
    for(int l,r,i=1;i<=n;i++)
    {
        read(l),read(r);
        tr.work(l,r);
    }
    printf("%d\n",tr.siz[tr.rt]-2);
    return 0;
}
View Code

 

posted @ 2019-07-01 10:27  LiGuanlin  阅读(299)  评论(0编辑  收藏  举报