Portal

Description

给出一个\(n(n\leq10^5)\)个数的数列\(\{a_n\}\)和\(m(m\leq10^5)\)个形如\((x,y)\)的变化,表示\(a_x\)可以变成\(y\)。我们称一个子序列是合法的当且仅当其中至多一个数发生变化后,其仍然是一个不降序列。求最长合法子序列的长度。

Solution

记\(a_i\)能变化的最小值为\(fr_i\),最大值为\(to_i\),\(dp[i]\)表示以\(a_i\)结尾的最长合法子序列的长度。则很容易得到:

\[ dp[i]=max\{dp[j]\}+1 \quad (j<i,to_j\leq a_i,a_j\leq fr_i) $$ 时间复杂度为$O(n^2)$。
考虑如何快速求出满足$to_j\leq a_i,a_j\leq fr_i$的$j$,可以用k-d树搞(可能被卡常),这里用CDQ分治解决。
每次考虑$dp[L..mid]$对$dp[mid+1..R]$的影响。对于$i\in[mid+1,R]$记录三元组$(a_i,fr_i,i)$,对于$j\in[L,mid]$记录三元组$(to_j,a_j,j)$,排序后用线段树可搞。具体来说,线段树上区间$[L_0,R_0]$维护满足$a_j\in[L_0,R_0]$的$dp[j]$的最大值。排序保证了$to_j\leq a_i$,并且询问处于最后。
> 时间复杂度$O(nlog^2n)$。

##Code
```cpp
//序列
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
inline char gc()
{
static char now[1<<16],*s,*t;
if(s==t) {t=(s=now)+fread(now,1,1<<16,stdin); if(s==t) return EOF;}
return *s++;
}
inline int read()
{
int x=0; char ch=gc();
while(ch<'0'||'9'<ch) ch=gc();
while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
return x;
}
int const N=1e5+10;
int const V=N;
int n,m;
struct rec{int a,fr,to,id;} r[N],r1[N];
int cmpM;
bool cmpR(rec x,rec y)
{
int x1,x2,y1,y2;
if(x.id<=cmpM) x1=x.to,x2=x.a;
else x1=x.a,x2=x.fr;
if(y.id<=cmpM) y1=y.to,y2=y.a;
else y1=y.a,y2=y.fr;
if(x1==y1) return x2==y2?x.id<y.id:x2<y2;
else return x1<y1;
}
int dp[N];
#define Ls (p<<1)
#define Rs ((p<<1)|1)
int rt; int maxV[N<<2],tag[N<<2];
void update(int p) {maxV[p]=max(maxV[Ls],maxV[Rs]);}
void change(int p,int x) {maxV[p]=tag[p]=x;}
void pushdw(int p) {if(tag[p]!=-1) change(Ls,tag[p]),change(Rs,tag[p]),tag[p]=-1;}
int L,R; int tr[N];
void ins(int p,int L0,int R0,int x)
{
if(L==L0&&R0==L) {change(p,max(maxV[p],x)); return;}
pushdw(p);
int mid=L0+R0>>1;
if(L<=mid) ins(Ls,L0,mid,x);
else ins(Rs,mid+1,R0,x);
update(p);
}
int query(int p,int L0,int R0)
{
if(L<=L0&&R0<=R) return maxV[p];
pushdw(p);
int mid=L0+R0>>1,res=0;
if(L<=mid) res=max(res,query(Ls,L0,mid));
if(mid<R) res=max(res,query(Rs,mid+1,R0));
return res;
}
void solve(int fr,int to)
{
if(fr==to) return;
int mid=fr+to>>1;
solve(fr,mid);
for(int i=fr;i<=to;i++) r1[i]=r[i];
cmpM=mid; sort(r1+fr,r1+to+1,cmpR);
change(rt,0);
for(int i=fr;i<=to;i++)
{
int t=r1[i].id;
if(t<=mid) L=r[t].a,ins(rt,1,V,dp[t]);
else L=1,R=r[t].fr,dp[t]=max(dp[t],query(rt,1,V)+1);
}
solve(mid+1,to);
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++) r[i].fr=r[i].to=r[i].a=read(),r[i].id=i;
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
r[x].fr=min(r[x].fr,y),r[x].to=max(r[x].to,y);
}
rt=1; memset(tag,-1,sizeof tag);
for(int i=1;i<=n;i++) dp[i]=1;
solve(1,n);
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}
```\]

BZOJ4553 - [TJOI2016]序列的更多相关文章

  1. 【BZOJ4553】[HAOI2016&TJOI2016]序列

    [BZOJ4553][HAOI2016&TJOI2016]序列 题面 bzoj 洛谷 题解 一定要仔细看题啊qwq... 我们设$mn[i],mx[i]$表示第$i$个位置上最小出现.最大出现 ...

  2. [BZOJ4553][HEOI2016]序列 CDQ分治

    4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小伙 ...

  3. cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )

    hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...

  4. 洛谷 P4093 [HEOI2016/TJOI2016]序列 解题报告

    P4093 [HEOI2016/TJOI2016]序列 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一 ...

  5. 洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP

    洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他. 玩具上有一个数列,数列中某些项的值可能会 ...

  6. [BZOJ4553][TJOI2016&&HEOI2016]序列(CDQ分治)

    4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 554[Su ...

  7. [BZOJ4553][Tjoi2016&Heoi2016]序列 cdp分治+dp

    4553: [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 260  Solved: 133[Sub ...

  8. bzoj4553 [Tjoi2016&Heoi2016]序列 树状数组(区间最大值)+cqd

    [Tjoi2016&Heoi2016]序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1006  Solved: 464[Submit][ ...

  9. BZOJ4553: [Tjoi2016&Heoi2016]序列

    Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值 可能会变化,但同一个时刻最多只有一个值发生变化.现在佳媛姐姐已经研究出了所 ...

随机推荐

  1. php数组与字符串转换

    1.将字符串转换成数组的几个函数: (1)explode(separate,string) 示例:$str = "Hello world It's a beautiful day" ...

  2. 高阶组件(Higher-Order Components)

    有时候人们很喜欢造一些名字很吓人的名词,让人一听这个名词就觉得自己不可能学会,从而让人望而却步.但是其实这些名词背后所代表的东西其实很简单. 我不能说高阶组件就是这么一个东西.但是它是一个概念上很简单 ...

  3. re正则表达式公式讲解1

    常用的表达式一些规则 1.“.”  匹配出了\n之外的任意一个字符,包括特殊字符 有几个·就匹配几个字符. import re print(re.search("."," ...

  4. hihocoder1718 最长一次上升子序列

    思路: 对于每个i,分别求1~i和i+1~N两部分的最长下降子序列“拼”起来,最终取最大长度即可.学习了如何使用BIT把LIS问题O(N2)算法优化为O(Nlog(N))的算法. https://ww ...

  5. 洛谷P1251 餐巾计划问题(最小费用最大流)

    题意 一家餐厅,第$i$天需要$r_i$块餐巾,每天获取餐巾有三种途径 1.以$p$的费用买 2.以$f$的费用送到快洗部,并在$m$天后取出 3.以$s$的费用送到慢洗部,并在$n$天后取出 问满足 ...

  6. 事件对象(示例、封装函数EventUtil())

    事件对象 什么是事件对象? 在触发DOM上的事件时都会产生一个对象. 事件对象event 1.DOM中的事件对象 (1)\type属性用于获取事件类型 (2)\target属性用于获取事件目标 (3) ...

  7. CSData

    NSString 转换成NSData 对象 NSData* xmlData = [@"testdata" dataUsingEncoding:NSUTF8StringEncodin ...

  8. 汇编3栈帧,参数传递,串操作,混合汇编,x64,asm文件

    基础知识2 选择结构 通过判断 + 条件跳转指令来实现 循环结构 通过判断 + 条件跳转指令来实现(会有一个向上跳转的语句) 函数调用约定 C调用约定: 由外部平衡栈 标准调用约定 : 由函数内部平衡 ...

  9. EEPROM的存储大小

    学习单片机时,常见的EEPROM如24C02的大小为2Kbit(有的也称2KB).这里的2KB到底能存储多少数据呢? 2KB中,B表示单位bit,K表示1024. 单片机编程中常用的数据类型为unsi ...

  10. 最短路 || HDU 2066 一个人的旅行

    本草的旅行故事(✺ω✺),可以从S个点中的任意一个开始,到达D个点中的任意一个,求最短路 *解法:把草儿的家记成点0,S个点与0的距离为0,然后spfa求最短路 又是改了一万次,①多组数据啊 ②改完多 ...