Codeforces 题目传送门 & 洛谷题目传送门

我怕不是个 nt……一开始忽略了”询问独立“这个条件……然后就一直在想有什么办法维护全局 LIS……心态爆炸

首先离散化。预处理出以每个点为结尾的 LIS 长度 \(f_i\),以及以每个点为开头的 LIS 长度 \(g_i\)。

不难发现每次只修改一个元素,故每次询问的答案只可能是原序列 LIS 的长度 \(mx\pm 1\)。

我们不妨来探究什么情况下询问的答案为 \(mx+1\),什么情况下询问的答案为 \(mx-1\)。

\(+1\) 的情况比较容易,只可能是存在一个通过 \(a_i\) 的长度为 \(mx+1\) 的上升序列,如果我们记 \(f'_i\) 为将 \(a_i\) 位置上的值换成 \(b_i\) 后,以 \(a_i\) 结尾的 LIS 的长度,\(g'_i\) 为将 \(a_i\) 位置上的值换成 \(b_i\) 后,以 \(a_i\) 开头的 LIS 的长度,那么新序列中经过 \(a_i\) 的上升序列的长度最大值即为 \(f'_i+g'_i-1\),故若 \(f'_i+g'_i-1=mx+1\),则新的 LIS 长度为 \(mx+1\)。

\(-1\) 的情况相对来说比较困难,新序列 LIS 的长度为 \(mx-1\) 需要两个条件,一是经过 \(a_i\) 的 LIS 长度 \(<mx\),二是所有长度为 \(mx\) 的上升子序列都经过 \(a_i\)。条件一比较容易检验,还是记 \(f'_i\) 为将 \(a_i\) 位置上的值换成 \(b_i\) 后,以 \(a_i\) 结尾的 LIS 的长度,那么经过 \(a_i\) 的 LIS 长度就是 \(f'_i+g'_i-1\)。比较麻烦的是条件二,一种可能的处理方式是在求 \(f_i\) 的同时求出 \(ed_i\) 表示有多少个长度为 \(f_i\) 的上升子序列以 \(i\) 结尾,\(st_i\) 表示有多少个长度为 \(g_i\) 的上升子序列以 \(i\) 开头,那么总共有 \(\dfrac{1}{mx}\sum\limits_{i}st_ied_i[f_i+g_i-1=mx]\) 个长度为 \(mx\) 的 LIS。检验是否所有长度为 \(mx\) 的上升子序列都经过 \(a_i\) 需要满足两个条件,一是 \(f_{a_i}+g_{a_i}-1=mx\),二是经过 \(a_i\) 的 LIS 的个数等于长度为 \(mx\) 的 LIS 的总个数,即 \(st_ied_i=\dfrac{1}{mx}\sum\limits_{i}st_ied_i[f_i+g_i-1=mx]\),由于 LIS 的个数很多,故这里的 \(f_i,g_i\) 需模上一个大质数,如 \(998244353\) 等,这个实现起来略有些困难,就不展开讲解了(估计 CF 上此题 hashing 的 tag 就是留给这个解法的罢)。

这里给出一个较为简便的做法,首先 \(f_{a_i}+g_{a_i}-1=mx\) 是必要条件,如果 \(f_{a_i}+g_{a_i}-1\neq mx\) 那肯定不满足条件,其次关于 LIS 有一个性质,那就是若 \(f_i+g_i-1=mx\),对于所有经过 \(i\) 的 LIS,该 LIS 中第 \(f_i\) 大的元素一定是 \(i\)。考虑反证法,设 \(i\) 是这样的 LIS 中第 \(j\) 个元素,若 \(j<f_i\),那么在 \(i\) 后面的元素有 \(mx-j>g_i\) 个,而根据 \(g_i\) 的定义知以 \(i\) 开头的 LIS 长度最大为 \(g_i\),矛盾,\(j>f_i\) 的情况也同理。考虑对于不经过 \(i\) 的 LIS,这样的 LIS 中第 \(f_i\) 大的元素是什么,根据之前的分析知假设第 \(f_i\) 大的元素是 \(j\),那么一定有 \(f_j=f_i\)。也就是说如果 \(f_j=f_{a_i},j\neq a_i\) 的 \(j\) 存在,那 \(a_i\) 就不符合题意。故只需开一个桶 \(c_i\) 表示有多少 \(f_j=i\) 的 \(j\) 并检验 \(c_{f_{a_i}}=1\) 即可。

至于怎么求 \(f_i,g_i\)……就按照套路把询问挂在 \(a_i\) 处,然后按照树状数组求 LIS 的套路扫描一遍即可。时间复杂度 \(n\log n\)。

那问题就来了,如果这题询问不独立怎么做呢?

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=4e5;
int n,qu,key[MAXN*2+5],uni[MAXN*2+5],num=0,cnt=0;
int a[MAXN+5],x[MAXN+5],y[MAXN+5];
int v[MAXN+5],nxt[MAXN+5],hd[MAXN+5],item_n=0;
void ins(int p,int q){v[++item_n]=q;nxt[item_n]=hd[p];hd[p]=item_n;}
int getnum(int x){
int l=1,r=num;
while(l<=r){
int mid=(l+r)>>1;
if(uni[mid]==x) return mid;
if(uni[mid]<x) l=mid+1;
else r=mid-1;
}
}
int f[MAXN+5],g[MAXN+5],qf[MAXN+5],qg[MAXN+5],c[MAXN+5];
int t[MAXN*2+5];
void add(int x,int v){for(int i=x;i<=num;i+=(i&(-i))) chkmax(t[i],v);}
int query(int x){int ret=0;for(int i=x;i;i&=(i-1)) chkmax(ret,t[i]);return ret;}
int main(){
scanf("%d%d",&n,&qu);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),key[++cnt]=a[i];
for(int i=1;i<=qu;i++) scanf("%d%d",&x[i],&y[i]),ins(x[i],i),key[++cnt]=y[i];
sort(key+1,key+cnt+1);
for(int i=1;i<=cnt;i++) if(key[i]!=key[i-1]) uni[++num]=key[i];
for(int i=1;i<=n;i++) a[i]=getnum(a[i]);
for(int i=1;i<=qu;i++) y[i]=getnum(y[i]);
for(int i=1;i<=n;i++) f[i]=query(a[i]-1)+1,add(a[i],f[i]);
memset(t,0,sizeof(t));
for(int i=n;i;i--) g[i]=query(num-a[i])+1,add(num-a[i]+1,g[i]);
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++){
for(int e=hd[i];e;e=nxt[e]){
int id=v[e];qf[id]=query(y[id]-1)+1;
} add(a[i],f[i]);
}
memset(t,0,sizeof(t));
for(int i=n;i;i--){
for(int e=hd[i];e;e=nxt[e]){
int id=v[e];qg[id]=query(num-y[id])+1;
} add(num-a[i]+1,g[i]);
}
int mx=0;
for(int i=1;i<=n;i++) chkmax(mx,f[i]+g[i]-1);
for(int i=1;i<=n;i++) if(f[i]+g[i]-1==mx) c[f[i]]++;
for(int i=1;i<=qu;i++){
if(qf[i]+qg[i]-1>mx) printf("%d\n",qf[i]+qg[i]-1);
else if(qf[i]+qg[i]-1<mx&&f[x[i]]+g[x[i]]-1==mx&&c[f[x[i]]]==1) printf("%d\n",mx-1);
else printf("%d\n",mx);
}
return 0;
}

Codeforces 650D - Zip-line(树状数组)的更多相关文章

  1. [Codeforces 1208D]Restore Permutation (树状数组)

    [Codeforces 1208D]Restore Permutation (树状数组) 题面 有一个长度为n的排列a.对于每个元素i,\(s_i\)表示\(\sum_{j=1,a_j<a_i} ...

  2. Codeforces 830B - Cards Sorting 树状数组

    B. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  3. codeforces 589G G. Hiring(树状数组+二分)

    题目链接: G. Hiring time limit per test 4 seconds memory limit per test 512 megabytes input standard inp ...

  4. CodeForces–830B--模拟,树状数组||线段树

    B. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  5. Codeforces 1139F Dish Shopping 树状数组套平衡树 || 平衡树

    Dish Shopping 将每个物品拆成p 和 s 再加上人排序. 然后问题就变成了, 对于一个线段(L - R), 问有多少个(li, ri)满足  L >= li && R ...

  6. CodeForces 522D Closest Equals 树状数组

    题意: 给出一个序列\(A\),有若干询问. 每次询问某个区间中值相等且距离最短的两个数,输出该距离,没有则输出-1. 分析: 令\(pre_i = max\{j| A_j = A_i, j < ...

  7. Codeforces 960F Pathwalks ( LIS && 树状数组 )

    题意 : 给出若干个边,每条边按照给出的顺序编号,问你找到一条最长的边权以及边的编号同时严格升序的一条路径,要使得这条路径包含的边尽可能多,最后输出边的条数 分析 :  这题和 LIS 很相似,不同的 ...

  8. CodeForces - 597C Subsequences (树状数组+动态规划)

    For the given sequence with n different elements find the number of increasing subsequences with k + ...

  9. codeforces Gym100589H Count Subarrays 树状数组/线段树+离散化

    题意:给你一个数组,问你有多少子数组中的逆元数不小于K个,N<105 还在研究中

随机推荐

  1. 利用python爬取全国水雨情信息

    分析 我们没有找到接口,所以打算利用selenium来爬取. 代码 import datetime import pandas as pd from bs4 import BeautifulSoup ...

  2. 初始HTML05

    HTML 表单控件属性 表单控件可设置以下标签属性 属性名 取值 type 设置控件类型 name 设置控件名称,最终与值一并发送给服务器 value 设置控件的值 placeholder 设置输入框 ...

  3. 什么,你还使用 webpack?别人都在用 vite 搭建项目了

    一.vite 到底是干嘛的? vite 实际上就是一个面向现代浏览器,基于 ES module 实现了一个更轻快的项目构建打包工具. vite 是法语中轻快的意思. vite 的特点: 1.轻快的冷服 ...

  4. SpringCloud-初见

    目录 前言 微服务概述 微服务与微服务架构 微服务优缺点 微服务技术栈 为什么选择SpringCloud作为微服务架构 SpringCloud入门 SpringCloud和SpringBoot的关系 ...

  5. 6. 站在巨人的肩膀学习Java Filter型内存马

    本文站在巨人的肩膀学习Java Filter型内存马,文章里面的链接以及图片引用于下面文章,参考文章: <Tomcat 内存马学习(一):Filter型> <tomcat无文件内存w ...

  6. Spring Cloud Alibaba 介绍及工程准备

    简介 SpringCloud Alibaba是阿里巴巴集团开源的一套微服务架构解决方案. 微服务架构是为了更好的分布式系统开发,将一个应用拆分成多个子应用,每一个服务都是可以独立运行的子工程.其中涵盖 ...

  7. Python课程笔记(八)

    一些简单的文件操作,学过linux的话理解感觉不会很难.课程代码 一.OS 目录方法 这个模块提供了一种方便的使用操作系统函数的方法 函数 说明 os.mkdir("path") ...

  8. 华为HCIP-Eth-trunk原理知识点

    Eth-trunk(端口聚合.链路捆绑.链路聚合.以太通道) Eth-trunk技术出现的原因: • 随着网络中部署的业务量不断增长,对于全双工点对点链路,单条物理链路的带宽已不能满足正常的业务流量 ...

  9. 21.8.7 test

    \(NOIP\) 测试 考的一般般. \(T1\) WOJ4656 签到题,其实就是算 \(\sum\limits_{i=1}^n i^2\) #include<bits/stdc++.h> ...

  10. Spark面试题整理(三)

    1.为什么要进行序列化序列化? 可以减少数据的体积,减少存储空间,高效存储和传输数据,不好的是使用的时候要反序列化,非常消耗CPU. 2.Yarn中的container是由谁负责销毁的,在Hadoop ...