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. 时间轮机制在Redisson分布式锁中的实际应用以及时间轮源码分析

    本篇文章主要基于Redisson中实现的分布式锁机制继续进行展开,分析Redisson中的时间轮机制. 在前面分析的Redisson的分布式锁实现中,有一个Watch Dog机制来对锁键进行续约,代码 ...

  2. vue介绍啊

    声明式渲染:vue的核心是一个允许你才用一个简洁的模板语法来声明式的将数据渲染进行DOM的系统 html部分:<div id="app"> {{message}}< ...

  3. JDK 8中重要的函数式接口(必知必会)

    JDK 8 提供的重要函数式接口: Consumer (消费者) 功能:接收一个对象,返回void. 定义:void accept(T t) 默认方法:Consumer andThen(Consume ...

  4. 代码混淆保安全「GitHub 热点速览 v.21.43」

    作者:HelloGitHub-小鱼干 虽然让代码难以阅读看似是件难以理解的事情,但是混淆后的代码起到了类似加密的作用,而且经过混淆的代码依旧能实现原代码的功能.javascript-obfuscato ...

  5. 类图示例-订单系统 / Class Diagram - Order System

    类图示例-订单系统 / Class Diagram - Order System 什么是类图? 类图通过显示它的类和它们之间的关系来概述系统.类图是静态的 - 它们显示交互的内容,但不显示交互时会发生 ...

  6. 联赛膜你测试20 T1 Simple 题解 && NOIP2017 小凯的疑惑 题解(赛瓦维斯特定理)

    前言: 数学题,对于我这种菜B还是需要多磨啊 Simple 首先它问不是好数的数量,可以转化为用总数量减去是好数的数量. 求"好数"的数量: 由裴蜀定理得,如果某个数\(i\)不能 ...

  7. MOSFET管驱动电路的设计

    https://wenku.baidu.com/view/ae727da5caaedd3382c4d3b9.html?mark_pay_doc=2&mark_rec_page=1&ma ...

  8. Xpath运算符

    5.position定位 >>print tree.xpath('//*[@id="testid"]/ol/li[position()=2]/text()')[0] & ...

  9. 像素设定 牛客网 程序员面试金典 C++ Python

    像素设定 牛客网 程序员面试金典 题目描述 有一个单色屏幕储存在一维数组中,其中数组的每个元素代表连续的8位的像素的值,请实现一个函数,将第x到第y个像素涂上颜色(像素标号从零开始),并尝试尽量使用最 ...

  10. cloudstack部署

    参考文档 https://blog.csdn.net/u012124304/article/details/80960504#Mysql_37 cloudstack的rpm包下载地址 http://d ...