首页 > 其他分享 >CF809D Hitchhiking in the Baltic States-平衡树+DP

CF809D Hitchhiking in the Baltic States-平衡树+DP

时间:2023-10-24 18:55:11浏览次数:34  
标签:ch int Hitchhiking States ge DP 序列 平衡 dp

CF809D Hitchhiking in the Baltic States-平衡树+DP

Statement

给出 \(n\) 个区间 \([l_i,r_i]\) 和 \(n\) 个未知数 \(a_1,a_2,\dots,a_n\),现在你要确定这 \(n\) 个数,使得 \(a_i\in[l_i,r_i]\),并且这个序列的最长严格上升子序列尽可能大,求这个最大值。

\(1 \leq n\leq 3\times 10^5\),\(1 \leq l_i,r_i\leq 10^9\)。

Solution

好题!很妙,非常妙!

首先感觉就很想 dp,

但是 dp 的方程式又很难推出来。。。

对于最长严格上升子序列,

我们进行套路性的操作:

设 \(dp[j]\) 表示最长严格上升子序列的长度为 \(j\) 时,最后一位最小的值。

很容易发现,\(dp[j]\) 一定时单调递增的。

所以我们现在考虑加入每一个元素时的转移:

令当前的 \(l_i,r_i\) 分别为 \(l,r\),每一次我们一定是从 \(dp[j-1]\) 转移到 \(dp[j]\):

  1. 当 \(dp[j-1] \lt l\) 时,\(dp[j]=\min(dp[j],l)\)。
  2. 当 \(l \le dp[j-1] \lt r\) 时,\(dp[j]=\min(dp[j],dp[j-1]+1)\)。
  3. 当 \(dp[j-1]\ge r\) 时,\(dp[j]=dp[j]\) ,即不变。

于是我们得到了 \(O(n^2)\) 的做法。

现在考虑如何优化呢?(很难想到平衡树)

发现每一次 \(+1\) 一定是最优的,

我们现在考虑把整个数列看成一个整体,

对于操作 \(2\) ,我们可以发现其实就是相当于把区间 \([l,r-1]\) 里面的数都 \(+1\),

然后再右移一位,

而这样做完了发现有两个位置出现了冲突:

  1. \(\lt l\) 的最大的数的后一位,发现这里本来是 \(\ge l\) 的最小的数,那经过一次变化后,这一位最有的一定是 \(l\)。
  2. 而对于后面冲突的 \(\ge r\) 的最小的数,它一定是不优的,直接删除。

这样的分析我们发现其实每一次操作就是在序列上面在 \(\lt l\) 的最大位置后面插入 \(l\),将 \([l,r-1]\) 区间 \(+1\) ,再删除之前就 \(\ge r\) 的最小的数,

这些操作都可以用平衡树维护。

于是我们就可以用平衡树和 DP 完成此题,

而最后的答案就是平衡树的 \(siz\) 。

(没有一过呜呜呜)

#include <bits/stdc++.h>
using namespace std;
mt19937 rd(time(0));

const int N=3e5+5;
int n,l,r,idx=0,rt,x,y,z;
struct Treap{
  int key,s[2],val,siz,tag;
}tr[N];

int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f; 
}

int nwnode(int v){
  tr[++idx].val=v;
  tr[idx].key=rd();
  tr[idx].siz=1;
  tr[idx].s[0]=tr[idx].s[1]=tr[idx].tag=0;
  return idx;
}

#define lc(p) tr[p].s[0]
#define rc(p) tr[p].s[1]
 
void pu(int p){tr[p].siz=tr[lc(p)].siz+tr[rc(p)].siz+1;}

void pd(int p){
  if(!p||!tr[p].tag) return ;
  if(lc(p)) tr[lc(p)].tag+=tr[p].tag,tr[lc(p)].val+=tr[p].tag;
  if(rc(p)) tr[rc(p)].tag+=tr[p].tag,tr[rc(p)].val+=tr[p].tag;
  tr[p].tag=0;
}

void split(int p,int k,int &x,int &y){
  if(!p){x=y=0;return;}
  pd(p);
  if(tr[p].val<=k) x=p,split(rc(p),k,rc(p),y);
  else y=p,split(lc(p),k,x,lc(p));
  pu(p);
}

int merge(int x,int y){
  if(!x||!y) return (x|y);
  pd(x);pd(y);
  if(tr[x].key<tr[y].key){
  	tr[x].s[1]=merge(tr[x].s[1],y);
  	pu(x);return x;
  }
  else{
  	tr[y].s[0]=merge(x,tr[y].s[0]);
  	pu(y);return y;
  }
}

int find(int x,int k){
  if(!k) return 0;
  while(233){
  	if(tr[lc(x)].siz>=k) x=lc(x);
  	else if(tr[lc(x)].siz+1<k) k-=tr[lc(x)].siz+1,x=rc(x);
  	else return x;
  }
}

int pre(int val){
  split(rt,val-1,x,y);
  int res=find(x,tr[x].siz);
  rt=merge(x,y);
  return res;
}

int nxt(int val){
  split(rt,val,x,y);
  int res=find(y,1);
  rt=merge(x,y);
  return res;
}

void ins(int val){
  split(rt,val,x,y);
  rt=merge(x,merge(nwnode(val),y));
}

void del(int val){
  split(rt,val,x,z);
  split(x,val-1,x,y);
  y=merge(tr[y].s[0],tr[y].s[1]);
  rt=merge(x,merge(y,z));
}

void update(int l,int r){
  split(rt,l-1,x,y);
  split(y,r,y,z);
  tr[y].tag++;tr[y].val++;
  rt=merge(merge(x,y),z);
}

int main(){
  /*2023.10.24 H_W_Y CF809D Hitchhiking in the Baltic States DP+Treap*/
  n=read();
  for(int i=1;i<=n;i++){
  	l=read();r=read();
  	if(i==1){ins(l);continue;}
  	int q=nxt(r-1);
  	update(l,r-1);
	ins(l);
  	if(q) del(tr[q].val); 
  }
  if(!rt) puts("0");
  else printf("%d\n",tr[rt].siz);
  return 0;
}

Conclusion

  1. 最长上升子序列:设 \(dp[j]\) 表示最长严格上升子序列的长度为 \(j\) 时,最后一位最小的值!!!
  2. dp 的优化可以考虑平衡树,将数列看作一个整体。

标签:ch,int,Hitchhiking,States,ge,DP,序列,平衡,dp
From: https://www.cnblogs.com/hwy0622/p/CF809D.html

相关文章

  • 好好回答下 TCP 和 UDP 的区别!
    写了这么多篇关于TCP和UDP的文章,还没有好好聊过这两个协议的区别,这篇文章我们就来开诚布公的谈一谈。关于TCP和UDP,想必大家都看过一张这样的图。有一个小姑娘在对着瓶口慢慢的喝水,下面写着可靠的传输,少女的衣服没有被水浸湿,这张图被称为TCP。然后又有一个小姑娘在举着水......
  • 利用docker安装wordpress
    ubuntu系统没有docker直接snapinstalldocker拉取wordpress镜像dockerpullwordpress:php7.3创建mysql数据文件夹mkdir-p/data/wordpress/运行mysql5.7镜像,没有会直接拉取dockerrun-d--namemy_mysql--restartalways-eMYSQL_ROOT_PASSWORD=redhat-eMYSQL_D......
  • 学校(抽象dp)
    题目简述选择的学校编号依次为\(p1,p2,p3,...,pk(1≤p1<p2<...<pk≤n)\),若存在\(i(1≤i≤k−3)\)使得$a_{p_i}⊕a_{p_{i+1}}⊕a_{p_{i+2}}⊕a_{p_{i+3}}=s$,则该序列不合法。求在所有\(2^{n−1}\)个可能的序列中问有多少个序列合法。你......
  • 使用 DDPO 在 TRL 中微调 Stable Diffusion 模型
    引言扩散模型(如DALL-E2、StableDiffusion)是一类文生图模型,在生成图像(尤其是有照片级真实感的图像)方面取得了广泛成功。然而,这些模型生成的图像可能并不总是符合人类偏好或人类意图。因此出现了对齐问题,即如何确保模型的输出与人类偏好(如“质感”)一致,或者与那种难......
  • Linux平台下Oracle数据泵备份(expdp)SHELL脚本
    数据泵是Oracle10g的新特性,10g以后的版本才有。关于数据泵的理论知识参考我的Blog:Oracle10gEXPDP和IMPDP使用说明http://www.cndba.cn/Dave/article/1115 Logicalbackup.sh#!/bin/ksh#####################################################################......
  • 网络tcp与udp协议
    TCP协议TCP(transportcontrolprotocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然......
  • C语言数据类型占用字节大小+modport存在的意义+传输延迟和惯性延迟+上下拉+forwarding
    C语言数据类型占用字节大小最大整形宽度是8字节。modport存在的意义似乎modport的存在没有意义了。只是将信号变得更冗长。但是又是有意义的,因为modport里的赋值变化是没有延迟的,而clocking受到配置的影响。https://blog.csdn.net/hh199203/article/details/127230498传输......
  • 使用Spring Integration接收TCP与UDP请求
    1.简介SpringIntegration是一个开源的项目,它是Spring生态系统的一部分,旨在简化企业集成(EnterpriseIntegration)的开发。它提供了一种构建消息驱动的、松散耦合的、可扩展的企业应用集成解决方案的方式。SpringIntegration基于SpringFramework构建,使开发者能够更容易地......
  • Rockchip RK3399 - DRM eDP驱动程序
    在《RockchipRK3399-DRM驱动程序》》我们已经介绍过了,RK3399有两个VOP,均可以支持HDMI、eDP、DP、MIPIDSI0、MIPIDSI1显示接口,本节我们选择eDP作为分析的对象。一、设备树配置1.1edp设备节点设备节点vopb下的子节点vopb_out_edp通过edp_in_vopb(由remote-endpoint属性指定)......
  • dpkg: error processing package *** (--configure)错误解决办法
    问题记录dpkg:errorprocessingpackage***(--configure)错误解决办法https://blog.csdn.net/dou3516/article/details/1051202211.sudomv/var/lib/dpkg/info//var/lib/dpkg/info_old/2.sudomkdir/var/lib/dpkg/info/3.sudoaptupdate......