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的更多相关文章

  1. 【Linux】解压分卷压缩的zip文件

    例如linux.zip.001, linux.zip.002, linux.zip.003. 1. cat linux.zip* > linux.zip #合并为一个zip包. 2. unzip ...

  2. zip文件自动打包

    简单的文件打包 首先是问题 我们有一个文件的文件过大,我需要删除或者压缩,当然我们就是选择压缩 如果是单个我们可以直接使用压缩功能 但是多个呢? 首先获取当前目录下的文件,使用 a=`ls` | te ...

  3. Self-organizing Maps及其改进算法Neural gas聚类在异常进程事件识别可行性初探

    catalogue . SOM简介 . SOM模型在应用中的设计细节 . SOM功能分析 . Self-Organizing Maps with TensorFlow . SOM在异常进程事件中自动分 ...

  4. 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 ...

  5. 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 ...

  6. PHP 与Python 读取大文件的区别

    php读取大文件的方法   <?php function readFile($file) { # 打开文件 $handle = fopen($file, 'rb'); while (feof($ ...

  7. 编译安装 codeblocks 20.03 mips64el

    期末考试要用哦,不然谁会愿意去踩这么多坑. qaq 龙梦 Fedora28 中有 codeblocks 17.12,但是 Ctrl-v 粘贴会闪退,导致压根不能用.Bing了一下发现这其实是 code ...

  8. 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 ...

  9. [SHA2017](web) writeup

    [SHA2017](web) writeup Bon Appétit (100) 打开页面查看源代码,发现如下 自然而然想到php伪协议,有个坑,看不了index.php,只能看 .htaccess ...

  10. pyspark 中的rdd api 编码练习

    1,使用pyspark 的rdd api 进行了数据文件的处理,包括构建RDD, 统计分析RDD ,从文件中读取数据RDD,从文件中构建 rdd的模式shema. 然后通过模式,从rdd中生成data ...

随机推荐

  1. Spring之webMvc异常处理

    异常处理可以前端处理,也可以后端处理. 从稳妥的角度出发,两边都应该进行处理. 本文专门阐述如何在服务端进行http请求异常处理. 一.常见的异常类型 当我们做http请求的时候,会有各种各样的可能错 ...

  2. 09-Python模块

    导入模块 通过import导入模块 import time #导入模块time time.sleep(50) #睡眠50s 导入模块并重命名 import time as t #导入模块time重命名 ...

  3. 在KEIL中用JTAG仿真出错:error:cannot load driver".....JL2CM3.dll" 时的解决方法

    在KEIL中用JTAG仿真出错:error:cannot load driver".....JL2CM3.dll" 时的解决方法 报错: Error:Cannot load dri ...

  4. Freertos学习:02-FreeRTOSConfig.h

    --- title: rtos-freertos-02-FreeRTOSConfig.h EntryName: rtos-freertos-02-FreeRTOSConfig date: 2020-0 ...

  5. 2024已过半,还没试过在vue3中使用ioc容器吗?

    Vue3 已经非常强大和灵活了,为什么还要引入 IOC 容器呢?IOC 容器离不开 Class,那么我们就从 Class 谈起 Class的应用场景 一提起 Class,大家一定会想到这是 Vue 官 ...

  6. redis-sort排序

    sort命令可以对列表(lpush rpush).集合(sadd srem).有序集合(zadd)进行排序 1.复习一下三种数据结构(1)列表 lpush  key val1 val2 val3 .. ...

  7. 我不应该用JWT的!

    一.前言 大家好呀,我是summo,之前有自学过Shrio框架,网上一搜就有SpringBoot整合Shrio+ JWT的文章,我是在学习Shrio框架的时候顺带学的JWT.后来我还看见有很多博主专门 ...

  8. SwiftUI学习01-基本使用

    SwiftUI 是苹果推出的一种现代化方式,用于创建跨所有 Apple 平台的用户界面.它通过声明性语法简化了 UI 的开发流程.下面是一个基本的 SwiftUI 示例,展示了如何使用 SwiftUI ...

  9. [oeasy]python0133_变量名_标识符_identifier_id_locals

    变量名 回忆上次内容 上次讲了 什么是变量 变量变量 能变的量 就是变量   各种系统.游戏就是由变量所组成的 ​   添加图片注释,不超过 140 字(可选)   声明了变量 并且 定义了变量   ...

  10. oeasy教您玩转vim - 89 - # 高亮细节Highlight

    ​ 高亮细节 highight 回忆 这个自动命令 autocmd 还是很方便的 打开时.保存时就会有自动执行的操作 自动命令有这么几大元素 {event} 触发事件 {pattern} 文件模式 { ...