【Codeforces809D】Hitchhiking in the Baltic States

来源:互联网 发布:网络直播电视机顶盒 编辑:程序博客网 时间:2024/06/05 17:57

dp[i]表示长度为i的序列最后一个数的最小值。
考虑转移时加入一段区间[l,r]
对于最大的满足dp[i]<l的位置:

dp[i+1]=min(dp[i+1],l)

因为dp[i+1]>=l,所以转移可以变为直接赋值(一定发生)。
对于最大的满足dp[j]<r的位置:
dp[k+1]=min(dp[k+1],dp[k]+1),k[i+1,j]

显然dp数组严格单调递增,即dp[i+1]>=dp[i]+1,所以上述转移必定发生。
所以我们可以通过一颗非旋转treap维护dp数组,每次删去dp[j+1]这个节点,对于dp[i+1]dp[j]这段dp区间整体+1并右移,再在原来的dp[i+1]前加入一个新的dp[i+1]=l的节点。这些操作都可以通过split,merge较为简单地实现。

#include <bits/stdc++.h>#define gc getchar()#define ll long long#define N 300009#define inf 0x3f3f3f3f#define rd(x) (rand()%(x))using namespace std;int n,l[N],r[N];struct node{    int size,val,key,add;    node *lson,*rson;    node(int v)    {        val=v;        key=rd(100000);        if (key<=0) key+=100000;        lson=rson=NULL;        size=1;        add=0;    }};typedef node * pnode;int read(){    int x=1;    char ch;    while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;    int s=ch-'0';    while (ch=gc,ch>='0'&&ch<='9') s=s*10+ch-'0';    return s*x;}void down(pnode now){    now->val+=now->add;    if (now->lson) now->lson->add+=now->add;    if (now->rson) now->rson->add+=now->add;    now->add=0;}pnode merge(pnode L,pnode R){    if (!L) return R;    if (!R) return L;    if (L->key>R->key)    {        down(L);        L->rson=merge(L->rson,R);        return L;    }    else    {        down(R);        R->lson=merge(L,R->lson);        return R;    }}void split(pnode now,int val,pnode &L,pnode &R){    if (!now)    {        L=R=NULL;        return;    }    down(now);    if (now->val>=val)    {        split(now->lson,val,L,now->lson);        R=now;        return;    }    else    {        split(now->rson,val,now->rson,R);        L=now;        return;    }}int find_begin(pnode now){    down(now);    if (!now->lson) return now->val;    return find_begin(now->lson);}int get_Ans(pnode now){    if (!now) return 0;    down(now);    return get_Ans(now->lson)+get_Ans(now->rson)+(now->val<inf);}pnode root,L,M,R,rest;int main(){    n=read();    for (int i=1;i<=n;i++) l[i]=read(),r[i]=read();    root=new node(0);    for (int i=1;i<=n;i++)        root=merge(root,new node(i+inf));    for (int i=1;i<=n;i++)    {        split(root,l[i],L,R);        split(R,r[i],M,R);        if (M) M->add++;        int Min=find_begin(R);        split(R,Min+1,rest,R);        root=merge(L,new node(l[i]));        root=merge(root,M);        root=merge(root,R);    }    printf("%d\n",get_Ans(root)-1);    return 0;}