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

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 809 D Hitchhiking in the Baltic States —— 思路+DP(LIS)+splay优化相关的知识,希望对你有一定的参考价值。

题目:http://codeforces.com/contest/809/problem/D

看题解,抄标程...发现自己连 splay 都快不会写了...

首先,题目就是要得到一个 LIS;

但与一般不同的是,新加入的不是一个值,而是一个取值范围;

仍是设 f[i] 表示长度为 i 的 LIS 的结尾最靠前是哪个位置,而此时新出现一个区间 l~r;

如果 f[i] < l,那么可以接上一个 l 变成 f[i+1],也就是 f[i+1] = l;

如果 l <= f[i] <= r,也可以把这个 f[i] 通过选这个区间里的值而尽量提前,最多能提前到上一个 f[j] , l <= f[j] < f[i] <= r;

也就是此时,f[i] = f[j] + 1;

可以知道上一个位置 j 就是 i-1,也就是新增区间带来了这样的转移:f[i] = min( f[i] , f[i-1] + 1),而 f[i-1] + 1 <= f[i] , 所以 f[i] = f[i-1] + 1;

综上,新增加一个区间:

1.会使 l 左边第一个 f[i] < l 转移到 f[i+1] = l;

2.使区间内部的值都向前跳到上一个的后一个,即 f[i+1] = f[i] + 1 , l <= f[i] < f[i+1] <= r;

3.使右边第一个 f[i] > r 转移到 f[i-1] + 1;

可以发现,转移2可以看做是区间内的 f[] 都向右移动了一下,然后区间左边第一个移动到了左端点,右边第一个移到区间内,同时角标(答案)+1;

就可以用 splay 维护,每次找到值在 l~r 范围内的,+1,再删除……,加入……什么的...

然后就模仿了标程的写法...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls c[x][0]
#define rs c[x][1]
using namespace std;
int const xn=3e5+5;
int n,Q,v[xn],lzy[xn],fa[xn],c[xn][2],rt,ans;
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=0; ch=getchar();}
    while(ch>=0&&ch<=9)ret=(ret<<3)+(ret<<1)+ch-0,ch=getchar();
    return f?ret:-ret;
}
void pushdown(int x)
{
    if(!lzy[x])return;
    v[ls]+=lzy[x]; lzy[ls]+=lzy[x];
    v[rs]+=lzy[x]; lzy[rs]+=lzy[x];
    lzy[x]=0;
}
void push(int x)
{
    if(fa[x])push(fa[x]);
    pushdown(x);
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],d=(c[y][1]==x);
    if(z)c[z][c[z][1]==y]=x;
    fa[x]=z; fa[y]=x; fa[c[x][!d]]=y;
    c[y][d]=c[x][!d]; c[x][!d]=y;
}
void splay(int x,int f)
{
    push(x);//!
    while(fa[x]!=f)
    {
        int y=fa[x],z=fa[y];
        if(z!=f)
        {
            if((c[y][0]==x)^(c[z][0]==y))rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if(!f)rt=x;
}
int low(int k)//<=k
{
    int nw=rt,ret=0;
    while(nw)
    {
        pushdown(nw);//!!!
        if(v[nw]<k)ret=nw,nw=c[nw][1];
        else nw=c[nw][0];
    }
    return ret;
}
int nxt(int x)
{
    splay(x,0); int nw=c[x][1];
    while(c[nw][0])nw=c[nw][0];
    return nw;
}
void insert(int &x,int k,int f)
{
    if(!x){v[x=++n]=k; fa[x]=f; splay(x,0); return;}
    pushdown(x);//!!
    insert(c[x][k>v[x]],k,x);
}
void del(int x)
{
    splay(x,0); int p=c[x][0],q=c[x][1];
    while(c[p][1])p=c[p][1];
    while(c[q][0])q=c[q][0];
    splay(p,0); splay(q,p);
    c[q][0]=0; fa[x]=0;
}
void solve(int l,int r)
{
    int p=low(l),q=low(r),t=nxt(q);
    if(p!=q)//!
    {
        splay(p,0); splay(t,p);
        v[c[t][0]]++; lzy[c[t][0]]++;    
    }
    if(t!=1)del(t),ans--;
    insert(p,l,0); ans++;
}
int main()
{
    Q=rd();
    v[++n]=(1<<30); v[++n]=-(1<<30); fa[2]=1; c[1][0]=2; rt=1;//
    for(int i=1,l,r;i<=Q;i++)l=rd(),r=rd(),solve(l,r);
    printf("%d
",ans);
    return 0;
}

 

以上是关于CF 809 D Hitchhiking in the Baltic States —— 思路+DP(LIS)+splay优化的主要内容,如果未能解决你的问题,请参考以下文章

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

CF809D Hitchhiking in the Baltic States DP平衡树

cf 809

CF809E Surprise me!

CF809E Surprise me!

CF809C Find a car