题意概述:

给出一个长度为N的序列和M组询问,问假设把某个位置的值改成另一个给出的值之后,序列的最长上升子序列的长度。

N,M<=400000.

分析:

考虑某个位置的值改动后这个位置和最长上升子序列(lis)的关系:

1、这个位置包含在lis中(这种情况答案可能+1,可计算经过这个点的lis来等效决策)。

2、这个位置不包含在lis中,那么需要看是否任意的lis都经过这个位置。如果是的话此决策的结果在原来长度基础上-1,否则就等于原来的长度。

有了大体思路,接下来想想维护。

任务1:对于任意位置x,求包含这个点的lis长度,令g1(i)表示1->N方向长度为i的lis的最长上升子序列的最后一个值的最小值,g2(i)表示N->1方向长度为i的最长下降子序列的最后一个值的最大值(更新就不说了,基础),如果知道位置x状态下恰好未更新的g1,g2数组内容,就同更新一样用前后以这个点结尾的最长序列长度相加-1就是此决策的结果。

任务2:这个实际上是重点,对于任意位置x,知道的东西和任务1一样,同时知道是否存在一对g1(a),g2(b)满足a+b=len(len是原序列lis长度)&&g1(a)<g2(b),如果存在那么此决策的结果为原来答案,否则为原来答案-1。

如果要强行在线的话三棵主席树维护一下两个g数组和一个vis数组(vis(x)表示对于当前状态来说g1(x),g2(len-x)是否合法,当前状态是否合法实际上就是看vis的所有值的和是否不为0)然后随便乱搞就可以了。

然而。。。我选择离线,询问按照位置排序,正反扫一遍序列处理第一种情况,然后再正着扫一遍把第二种情况用一个数组处理了就可以了。能离线何苦去在线码主席树呢(手动滑稽)(手动链表或者vector都可以帮忙离线)?!!

然而我还是弄了半天,污浊的机房CO2,QAQ

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=; int N,M,h[maxn];
struct que{
int id,pos,v;
friend bool operator < (que a,que b){
return a.pos<b.pos;
}
}q[maxn];
int g1[maxn],g2[maxn],cnt1,cnt2,ans[maxn],len,vis[maxn];
struct mlink{
static const int max_sz=;
int np,w[maxn],first[maxn],next[maxn];
mlink(){
np=,w[]=next[]=;
memset(first,,sizeof(first));
}
void ins(int i,int x) { w[++np]=x,next[np]=first[i],first[i]=np; }
void del(int i) { first[i]=next[first[i]]; }
int val(int i) { return w[first[i]]; }
}dd; void data_in()
{
scanf("%d%d",&N,&M);
for(int i=;i<=N;i++) scanf("%d",&h[i]);
for(int i=;i<=M;i++){
scanf("%d%d",&q[i].pos,&q[i].v);
q[i].id=i;
}
sort(q+,q+M+);
}
bool cmp(int x,int y) { return x>y; }
void work()
{
for(int i=;i<=N;i++){
int j=lower_bound(q+,q+M+,(que){,i,})-q;
while(j<=M&&q[j].pos==i)
ans[q[j].id]=lower_bound(g1+,g1+cnt1+,q[j].v)-g1,j++;
int x=lower_bound(g1+,g1+cnt1+,h[i])-g1;
if(x>cnt1) cnt1=x;
g1[x]=h[i];
}
for(int i=N;i>=;i--){
int j=lower_bound(q+,q+M+,(que){,i,})-q;
while(j<=M&&q[j].pos==i)
ans[q[j].id]+=lower_bound(g2+,g2+cnt2+,q[j].v,cmp)-g2-,j++;
int x=lower_bound(g2+,g2+cnt2+,h[i],cmp)-g2;
if(x>cnt2) cnt2=x;
g2[x]=h[i];
dd.ins(x,g2[x]);
}
memset(g1,,sizeof(g1)); len=cnt1,cnt1=;
int x=lower_bound(g2+,g2+cnt2+,h[],cmp)-g2,sum=;
dd.del(x); g2[x]=dd.val(x);
if(g2[len]) vis[]=,sum++;
for(int i=;i<=N;i++){
int j=lower_bound(q+,q+M+,(que){,i,})-q;
while(j<=M&&q[j].pos==i)
ans[q[j].id]=max(ans[q[j].id],len-(sum==)),j++;
int x1=lower_bound(g1+,g1+cnt1+,h[i])-g1;
if(x1>cnt1) cnt1=x1; g1[x1]=h[i];
int x2=lower_bound(g2+,g2+cnt2+,h[i+],cmp)-g2;
dd.del(x2); g2[x2]=dd.val(x2);
if(!g2[x2]) cnt2--;
if((x1==len||g1[x1]<g2[len-x1])&&!vis[x1]) vis[x1]=,sum++;//请注意这一句的第一个条件
if(g1[len-x2]>=g2[x2]&&vis[len-x2]) vis[len-x2]=,sum--;
}
for(int i=;i<=M;i++) printf("%d\n",ans[i]);
}
int main()
{
data_in();
work();
return ;
}

Codeforces Round #345 Div.1 D.Zip-line 动态最长上升子序列的更多相关文章

  1. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

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

  3. Codeforces Round #345 (Div. 2) B. Beautiful Paintings 暴力

    B. Beautiful Paintings 题目连接: http://www.codeforces.com/contest/651/problem/B Description There are n ...

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

  5. Codeforces Round #345 (Div. 1) C. Table Compression dp+并查集

    题目链接: http://codeforces.com/problemset/problem/650/C C. Table Compression time limit per test4 secon ...

  6. Codeforces Round #345 (Div. 2) E. Table Compression 并查集

    E. Table Compression 题目连接: http://www.codeforces.com/contest/651/problem/E Description Little Petya ...

  7. codeforces Codeforces Round #345 (Div. 1) C. Table Compression 排序+并查集

    C. Table Compression Little Petya is now fond of data compression algorithms. He has already studied ...

  8. Codeforces Round #345 (Div. 2)【A.模拟,B,暴力,C,STL,容斥原理】

    A. Joysticks time limit per test:1 second memory limit per test:256 megabytes input:standard input o ...

  9. Codeforces Round #345 (Div. 1) E. Clockwork Bomb 并查集

    E. Clockwork Bomb 题目连接: http://www.codeforces.com/contest/650/problem/E Description My name is James ...

  10. Codeforces Round #345 (Div. 2) D. Image Preview 暴力 二分

    D. Image Preview 题目连接: http://www.codeforces.com/contest/651/problem/D Description Vasya's telephone ...

随机推荐

  1. IPv4和IPv6的兼容问题

    一网络拓扑 Ipv6网络1 路由器A IPv4网络 路由器B IPv6网络2 二知识补充 [注]双协议栈主机(路由器A.B)通过域名解析器区分传过来的是IPv4还是IPv6 三处理技术 双协议栈 Ip ...

  2. Block代替delegate,尽量使用block,对于有大量的delegate方法才考虑使用protocol实现.

    Block代替delegate,尽量使用block,对于有大量的delegate方法才考虑使用protocol实现. 1.Block语法总结及示例如下:         //1.普通代码块方式bloc ...

  3. python 之函数

    一 函数的定义:对功能和动作的封装和定义.二 函数的格式:def 函数名(形参列表): 函数名就是变量名:规则就是变量的规则 函数体(return) ret = 函数名(实参列表)三 函数的返回值:函 ...

  4. oracle的事务隔离级别和读一致性

    oracle提供了三个隔离级别: 1.读提交 ,简而言之只能读取语句开始执行前提交的数据 2.串行,这个好理解,就是事务串行运行,避免经典的三个场景-脏读.不可重复读.幻读. 3.只读,oracle已 ...

  5. C#中委托和代理的深刻理解(转载)

    在写代码的过程中遇到了一个问题,就是" .net CallbackOnCollectedDelegate 垃圾回收问题. " 使用全局钩子的时候出现: globalKeyboard ...

  6. 2019-04-10 python入门学习——教材和工具准备

    # 从决定学习编程语言到正式做出计划挤出空余时间,历经一年半,因工作原因及生活原因不断搁浅,从湖北到浙江再回湖北,暂时稳定在一家小公司,从日常加班中压缩时间学习,于此记录学习进度.学习问题,在此过程中 ...

  7. Leecode刷题之旅-C语言/python-70爬楼梯

    /* * @lc app=leetcode.cn id=70 lang=c * * [70] 爬楼梯 * * https://leetcode-cn.com/problems/climbing-sta ...

  8. 分享一个根据具体的日期判断星座的PHP函数

    其实原理很简单,也就是把所有的星座月份日期范围存储到一个数组中,然后根据日期判断属于哪个范围,这样就得到是哪个星座了. 下面的这个函数写的比较精炼,可以参考一下 function constellat ...

  9. react-router 4.0中跳转失灵

    在https://github.com/ReactTraining/history文档中,跳转是 用这种方法,但是,用了之后就存在这么一个问题,网址换了但是页面并没有刷新. 查了资料后,history ...

  10. IDEA常用操作(一)

    1.视图的调整 左下右的侧边栏如何关闭?——右击选择remove from sidebar 面板上(左下右)的导航栏视图如何隐藏——可以在左下角悬停显示,单击隐藏/开启侧边栏 想打开其它视图怎么办?— ...