Codeforces 650D - Zip-line(树状数组)
我怕不是个 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(树状数组)的更多相关文章
- [Codeforces 1208D]Restore Permutation (树状数组)
[Codeforces 1208D]Restore Permutation (树状数组) 题面 有一个长度为n的排列a.对于每个元素i,\(s_i\)表示\(\sum_{j=1,a_j<a_i} ...
- Codeforces 830B - Cards Sorting 树状数组
B. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- codeforces 589G G. Hiring(树状数组+二分)
题目链接: G. Hiring time limit per test 4 seconds memory limit per test 512 megabytes input standard inp ...
- CodeForces–830B--模拟,树状数组||线段树
B. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- Codeforces 1139F Dish Shopping 树状数组套平衡树 || 平衡树
Dish Shopping 将每个物品拆成p 和 s 再加上人排序. 然后问题就变成了, 对于一个线段(L - R), 问有多少个(li, ri)满足 L >= li && R ...
- CodeForces 522D Closest Equals 树状数组
题意: 给出一个序列\(A\),有若干询问. 每次询问某个区间中值相等且距离最短的两个数,输出该距离,没有则输出-1. 分析: 令\(pre_i = max\{j| A_j = A_i, j < ...
- Codeforces 960F Pathwalks ( LIS && 树状数组 )
题意 : 给出若干个边,每条边按照给出的顺序编号,问你找到一条最长的边权以及边的编号同时严格升序的一条路径,要使得这条路径包含的边尽可能多,最后输出边的条数 分析 : 这题和 LIS 很相似,不同的 ...
- CodeForces - 597C Subsequences (树状数组+动态规划)
For the given sequence with n different elements find the number of increasing subsequences with k + ...
- codeforces Gym100589H Count Subarrays 树状数组/线段树+离散化
题意:给你一个数组,问你有多少子数组中的逆元数不小于K个,N<105 还在研究中
随机推荐
- SharkCTF2021 Classic_Crypto_king2
crypto类题. 题面如下: 前面的代码给出了原理:后面的字符串第一行是print出的key,第二行是密文. 加密原理是,首先对table进行乱序处理,然后将明文flag按照(顺序table--&g ...
- 三分钟极速体验:Java版人脸检测
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- GT考试
比较神仙的$dp+KMP+Matrix$综合题目,比较值得一写 $0x00$:首先我打了一个爆搜 不过对正解并无任何启发...(逗比发言请忽略) $0x01$:基础$dp$ 状态还是比较好设的, 考虑 ...
- 热身训练1 Game
http://acm.hdu.edu.cn/showproblem.php?pid=5242 简要题意: 一棵树有n个节点,每个节点x有一个权值wi,我们要从根节点出发(不可回头),去收集每个节点的权 ...
- 2021 CCPC女生赛
newbie,A了五题铜牌收工 比赛时和队友悠哉游哉做题,想着干饭,最后幸好没滚出铜尾. 贴一下比赛过的代码 A题 签到 队友A的,判断正反方向序列是否符合要求 /*** * @Author: _Kr ...
- MySQL实战优化之InnoDB整体架构
一.InnoDB 更新数据得整体架构 每个组件的作用说明: 用一条更新数据来说明每个主键得作用: update student set name = 'zhangsan' where id = 10 ...
- Serverless 工程实践|自建 Apache OpenWhisk 平台
作者 | 刘宇(江昱) 前言:OpenWhisk 是一个开源.无服务器的云平台,可以在运行时容器中通过执行扩展的代码响应各种事件,而无须用户关心相关的基础设施架构. OpenWhisk 简介 Open ...
- uni-app(Vue)中(picker)用联动(关联)选择以至于完成某些功能
如下图所示,在项目中需求是通过首先选择学生的专业,选好之后在每个专业下面选择对应的学期,每个学期有对应的学费,因此就需要联动选择来实现这一功能. 以下仅展示此功能主要代码: <div class ...
- 你说说RPC的一个请求的流程是怎么样的?
前言 面试的时候经常被问到RPC相关的问题,例如:你说说RPC实现原理.让你实现一个RPC框架应该考虑哪些地方.RPC框架基础上发起一个请求是怎样一个流程等等.所以这次我就总结一波RPC的相关知识点, ...
- c++ template 实现一个简单的"栈"
一: 实现一个简单的swap 原来我们写swap一定会这样写: 对于int类型的: swap(const int &x,const int &y) { int temp; temp = ...