• 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;
    }
  • 相关阅读:
    【网易官方】极客战记(codecombat)攻略-森林-加农炮之舞forest-cannon-dancing
    【网易官方】极客战记(codecombat)攻略-森林-森林慢跑forest-jogging
    https://developer.android.com/codelabs/java-to-kotlin
    今日英语
    架构师技能图谱
    java接口防重提交如何处理
    看看人家那后端API接口写得,那叫一个优雅!
    MySQL不推荐使用uuid或者雪花id作为主键
    “12306”是如何支撑百万QPS的?
    阿里巴巴为什么能抗住90秒100亿?看完这篇你就明白了!
  • 原文地址:https://www.cnblogs.com/Zinn/p/9721051.html
Copyright © 2020-2023  润新知