CF650D Zip-line
大概题面:
给定一个长度为 \(n\) 的序列以及\(m\)个操作,每个操作形如“ \(a_i,b_i\) ”,表示将序列中第 \(a_i\) 个数改为 \(b_i\) .对于每个操作,求出序列的最长严格上升子序列长度。
注意:每个操作之间彼此独立。(即每次操作未进行时的序列是输入时的原序列,而不是上一次操作后得到的序列)
\(1 \leq n,m \leq 400,000\),元素与\(b_i \leq 10^9\)
每次操作会修改一个数,每次要求LIS (求LIS)
暴力做法每次都做修改,重新求一次LIS,复杂度 \(O(n^2logn)\)
考虑每次修改会对答案造成什么影响。设 \(f_i\) 为以 \(i\) 结尾的LIS,设 \(g_i\) 为以 \(i\) 开头的LIS
那么修改前的LIS是 \(ans1=max(f_i+g_i-1)\) (或者说就是 \(ans1=max(f_i)\) )
再预处理出修改后每个询问的左右两边的 \(f_i’\) 和 \(g_i’\)
可能在修改后,恰好能将两侧的答案接起来,并让答案更长,此时询问的答案为 \(f_i'+g_i'+1\)
否则要判断在修改了当前节点后有没有影响。如果当前位置一定在原来的LIS上,则答案为 \(ans1-1\) ,否则为 \(ans1\) 。
*如何判断是否在LIS的必经点上?
首先,如果\(i\)在LIS上,则\(i\)一定在LIS的第\(f_i\)位。(因为\(f_i\)极大)
所以如果在其他所有满足 \(f_j+g_j-1=ans1\) 的\(j\)中,不存在 \(f_i=f_j\) ,那么它一定在LIS的必经点上。(如果存在 \(f_i=f_j\) ,则当前这一位\(i\)可以被替换成\(j\),不对答案有影响)
所以可以用二分+辅助数组求出 \(f_i\) , \(g_i\) ,\(f_i’\) 和 \(g_i’\) ,开桶统计 \(f_i\) 和出现的位置,判断一下即可。
时间 \(O(nlogn)\) ,可以通过。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=400005;
const int inf=0x3f3f3f3f;
inline int read(){
int f=1,x=0;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return f*x;
}
int n,q;
int a[N];
struct node{
int x,val,id;
int f,g; //在询问点左右两边的最大f, g
bool operator<(const node& p)const{
return x<p.x;
}
}op[N];
int f[N],g[N];
int fx[N];
int ans1;
int tong[N],pos[N];
int ans[N];
inline void work1(){ //求出f,g
for(int i=1;i<=n;i++)fx[i]=inf;
for(int i=1;i<=n;i++){
int l=1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(a[i]>fx[mid])l=mid;
else r=mid-1;
}
if(a[i]>fx[l])f[i]=l+1;
else f[i]=1;
fx[f[i]]=min(fx[f[i]],a[i]);
}
for(int i=1;i<=n;i++)fx[i]=0;
for(int i=n;i>=1;i--){ //相当于从右往左下降了
int l=1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(a[i]<fx[mid])l=mid;
else r=mid-1;
}
if(a[i]<fx[l])g[i]=l+1;
else g[i]=1;
fx[g[i]]=max(fx[g[i]],a[i]);
}
for(int i=1;i<=n;i++){
ans1=max(ans1,f[i]);
}
}
inline void work2(){ //处理询问
for(int i=1;i<=n;i++)fx[i]=inf;
int now=0;
for(int i=1;i<=q;i++){
for(int j=now+1;j<=op[i].x-1;j++){ //在询问点左侧最大的f
fx[f[j]]=min(fx[f[j]],a[j]);
}
int l=1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(op[i].val>fx[mid])l=mid;
else r=mid-1;
}
if(op[i].val>fx[l])op[i].f=l;
else op[i].f=0;
now=op[i].x-1;
}
for(int i=1;i<=n;i++)fx[i]=0;
now=n+1;
for(int i=q;i>=1;i--){
for(int j=now-1;j>=op[i].x+1;j--){ //在询问点右侧最大的g
fx[g[j]]=max(fx[g[j]],a[j]);
}
int l=1,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(op[i].val<fx[mid])l=mid;
else r=mid-1;
}
if(op[i].val<fx[l])op[i].g=l;
else op[i].g=0;
now=op[i].x+1;
}
for(int i=1;i<=n;i++){
if(f[i]+g[i]-1!=ans1)continue;
tong[f[i]]++;
if(tong[f[i]]==1)pos[f[i]]=i; //f[i]出现一次要记录
else pos[f[i]]=0;
}
}
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=q;i++){
op[i].x=read(),op[i].val=read();
op[i].id=i;
}
sort(op+1,op+1+q);
work1();
work2();
for(int i=1;i<=q;i++){
int x=op[i].x,id=op[i].id;
int f1=op[i].f,g1=op[i].g;
if(pos[f[x]]==x)ans[id]=max(ans1-1,f1+g1+1); //是关键位置就是ans1-1
else ans[id]=max(ans1,f1+g1+1);
}
for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
return 0;
}
这份代码在CodeForces上 \(624ms\) 通过。
CF650D Zip-line的更多相关文章
- 【Linux】解压分卷压缩的zip文件
例如linux.zip.001, linux.zip.002, linux.zip.003. 1. cat linux.zip* > linux.zip #合并为一个zip包. 2. unzip ...
- zip文件自动打包
简单的文件打包 首先是问题 我们有一个文件的文件过大,我需要删除或者压缩,当然我们就是选择压缩 如果是单个我们可以直接使用压缩功能 但是多个呢? 首先获取当前目录下的文件,使用 a=`ls` | te ...
- Self-organizing Maps及其改进算法Neural gas聚类在异常进程事件识别可行性初探
catalogue . SOM简介 . SOM模型在应用中的设计细节 . SOM功能分析 . Self-Organizing Maps with TensorFlow . SOM在异常进程事件中自动分 ...
- Codeforces Round #345 (Div. 1) D. Zip-line 上升子序列 离线 离散化 线段树
D. Zip-line 题目连接: http://www.codeforces.com/contest/650/problem/D Description Vasya has decided to b ...
- CodeForces - 650D:Zip-line (LIS & DP)
Vasya has decided to build a zip-line on trees of a nearby forest. He wants the line to be as long a ...
- PHP 与Python 读取大文件的区别
php读取大文件的方法 <?php function readFile($file) { # 打开文件 $handle = fopen($file, 'rb'); while (feof($ ...
- 编译安装 codeblocks 20.03 mips64el
期末考试要用哦,不然谁会愿意去踩这么多坑. qaq 龙梦 Fedora28 中有 codeblocks 17.12,但是 Ctrl-v 粘贴会闪退,导致压根不能用.Bing了一下发现这其实是 code ...
- codeforces #345 (Div. 1) D. Zip-line (线段树+最长上升子序列)
Vasya has decided to build a zip-line on trees of a nearby forest. He wants the line to be as long a ...
- [SHA2017](web) writeup
[SHA2017](web) writeup Bon Appétit (100) 打开页面查看源代码,发现如下 自然而然想到php伪协议,有个坑,看不了index.php,只能看 .htaccess ...
- pyspark 中的rdd api 编码练习
1,使用pyspark 的rdd api 进行了数据文件的处理,包括构建RDD, 统计分析RDD ,从文件中读取数据RDD,从文件中构建 rdd的模式shema. 然后通过模式,从rdd中生成data ...
随机推荐
- 2>&1解释
场景 /root/test.sh > runoob.log 2>&1 那2>&1是什么意思? 解释 将标准错误 2 重定向到标准输出 &1 ,标准输出 &am ...
- 一款.NET开源的i茅台自动预约小助手
前言 今天大姚给大家分享一款.NET开源.基于WPF实现的i茅台APP接口自动化每日自动预约(抢茅台)小助手:HyggeImaotai. 项目介绍 该项目通过接口自动化模拟i茅台APP实现每日自动预约 ...
- Android Verified Boot介绍与有关使用
Android Verified Boot介绍与有关使用 背景 在搞安卓驱动调试的时候,由于不熟悉,导致系统没有按照我预期启动完毕:因此需要注意这一块的东西. 简介 Verified Boot 是 A ...
- STM32的内存管理(转)
背景 这里针对STM32F407芯片+1M外部内存的内存管理!(全篇是个人愚见,如果错误,请不吝指出!) 定义 首先,定义3个内存池,分别是内部SRAM,外表SRAM和CCM:通过指定内存中的绝对地址 ...
- scarpy基础
1. 创建项目 scrapy startproject 项目名称 2. 进入项目 cd 项目名称 3. 创建爬虫 scrapy genspider 名字 域名 4. 可能需要start_urls,修改 ...
- 深耕分析型数据库领域,火山引擎ByteHouse入围《2024爱分析数据库厂商全景报告》
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群. 近日,爱分析发布<2024爱分析·数据库厂商全景报告>,报告中爱分析将数据市场从上至下划分为数据库服 ...
- Mybatis 快速入门(注解方式)
导读 注解开发的方式只需要程序员开发Mapper接口即可,不需要编写映射文件(XML). 环境搭建 项目结构 SqlMapConfig.xml <!DOCTYPE configuration P ...
- [oeasy]python0078_变量部分总结_variable_summary
删除变量 回忆上次内容 上次研究了变量的死 有生就有死 原本的死是在程序退出的时候自动执行的 也可以手动给变量执行死刑 del del(a)之后 dir()就无法在当前作用域(scope)内观 ...
- oeasy教您玩转python - 9 - # 换行字符
换行字符 回忆上次内容 数制可以转化 bin(n)可以把数字转化为 2进制 hex(n)可以把数字转化为 16进制 int(n)可以把数字转化为 10进制 编码和解码可以转化 encode 编码 ...
- FFmpeg开发笔记(四十)Nginx集成rtmp模块实现RTMP推拉流
<FFmpeg开发实战:从零基础到短视频上线>一书的"10.2.2 FFmpeg向网络推流"介绍了轻量级流媒体服务器MediaMTX,虽然MediaMTX使用很简单, ...