• 【CF809D】Hitchhiking in the Baltic States(Splay,动态规划)


    【CF809D】Hitchhiking in the Baltic States(Splay,动态规划)

    题面

    CF
    洛谷

    题解

    朴素(dp):设(f[i][j])表示当前考虑到第(i)个元素,结尾位置是(j)的最大选择数。
    然而这样就很呆。
    换个状态:设(f[i][j])表示当前考虑到第(i)个元素,长度为(j)时,最后一个数可以选择的最小值。
    这个东西看起来就舒服多了。
    (Splay)维护第二维,考虑每次加入一个区间对于答案的影响,假装当前加入区间是([l,r])
    首先是当前这个值不放入序列中,转移是(f[i][j]leftarrow f[i-1][j])
    然后就是当前值放入到序列中,大力分类讨论一下,
    如果(f[i-1][j-1]lt l),那么(f[i][j]leftarrow l)
    如果(f[i-1][j-1]in [l,r)),那么(f[i][j]leftarrow f[i-1][j-1]+1)
    如果(f[i-1][j-1]ge r),那么没有转移。

    显然第二维的值是单调不降的,因此修改的就是三段不同的区间。

    第一种转移显然只会修改最后一个(f[i-1][j-1]<l)的位置,这个东西直接赋值就好了(因为下一个一定(ge l))。
    因为数组单调,显然第二个转移只要存在必定就会转移。
    那么我们直接区间加法就好了。。。吗?
    发现这里还需要做一个区间平移。
    其实很好办,先把原先的(f[j])删掉,其中(j)是最大的满足(f[j]<r)的位置,然后在那个直接赋值的位置的地方直接插入一个(f[]=l)的东西,这样子就实现了前两个转移。
    然后就Splay xjb搞搞就行了。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MAX 300300
    #define ls (t[x].ch[0])
    #define rs (t[x].ch[1])
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Node{int ch[2],ff,v,tag;}t[MAX];
    int tot,ans,n;
    void rotate(int x)
    {
    	int y=t[x].ff,z=t[y].ff;
    	int k=t[y].ch[1]==x;
    	if(z)t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
    	t[y].ch[k]=t[x].ch[k^1];if(t[x].ch[k^1])t[t[x].ch[k^1]].ff=y;
    	t[x].ch[k^1]=y;t[y].ff=x;
    }
    void pushdown(int x)
    {
    	if(!t[x].tag)return;int w=t[x].tag;
    	if(ls)t[ls].v+=w,t[ls].tag+=w;
    	if(rs)t[rs].v+=w,t[rs].tag+=w;
    	t[x].tag=0;
    }
    int S[MAX],top,root;
    void Splay(int x,int goal)
    {
    	S[top=1]=x;
    	for(int i=x;t[i].ff;i=t[i].ff)S[++top]=t[i].ff;
    	while(top)pushdown(S[top--]);
    	while(t[x].ff!=goal)
    	{
    		int y=t[x].ff,z=t[y].ff;
    		if(z!=goal)
    			(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    		rotate(x);
    	}
    	if(!goal)root=x;
    }
    int Find(int val)
    {
    	int x=root,ret=0;
    	while(x)
    	{
    		pushdown(x);
    		if(t[x].v<val)ret=x,x=rs;
    		else x=ls;
    	}
    	return ret;
    }
    int Getnxt(int x){Splay(x,0);x=rs;while(ls)x=ls;return x;}
    int Getpre(int x){Splay(x,0);x=ls;while(rs)x=rs;return x;}
    void Delete(int x)
    {
    	int pre=Getpre(x),nxt=Getnxt(x);
    	Splay(pre,0);Splay(nxt,pre);
    	t[nxt].ch[0]=0;t[x].ff=0;
    }
    void Insert(int val)
    {
    	int x=root,fa=0;
    	while(x)
    	{
    		pushdown(x);fa=x;
    		if(t[x].v<=val)x=rs;
    		else x=ls;
    	}
    	x=++tot;
    	if(fa)t[fa].ch[t[fa].v<=val]=x;
    	t[x].ff=fa;t[x].v=val;Splay(x,0);
    }
    void Solve(int l,int r)
    {
    	int u=Find(l),v=Find(r),nt=Getnxt(v);
    	if(u^v)
    	{
    		Splay(u,0);Splay(nt,u);
    		int QwQ=t[nt].ch[0];
    		t[QwQ].v+=1;t[QwQ].tag+=1;
    	}
    	if(nt!=2)Delete(nt),--ans;
    	Insert(l),++ans;
    }
    int main()
    {
    	n=read();Insert(-1e9-5);Insert(+1e9+5);ans=0;
    	for(int i=1,l,r;i<=n;++i)l=read(),r=read(),Solve(l,r);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    又是七月的尾巴
    在Macbook Air上安装Archlinux
    又是一年毕业季
    orgpage a static site generator for emacs and org mode
    看完了《三体》三部曲
    暴强的命令行git提交历史记录查询
    xaml的window的AllowsTransparency属性在winxp下好像有bug,不知还有谁遇到过
    Swift 计算字符串展示的区域
    SwiftUI Stack中的View被压缩的效果
    如果git pull拉取分支出错,如何返回
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10490814.html
Copyright © 2020-2023  润新知