【bzoj4553】【Tjoi2016】【Heoi2016】【序列】【树套树】【线段树套线段树】
来源:互联网 发布:淘宝发布宝贝没有规格 编辑:程序博客网 时间:2024/06/07 14:40
题目大意
给出长度为n的序列a,有m次变化。每次变化把a[x]改成b[x],一个位可以多次修改,变化相对独立。选出最长字串,在m次变化与原串中都是不下降的。
题解
通过分析可知,设f[i]为前i位中一定选了i所形成的最长不下降字串的长度,f[i]可以转移到f[j] (j>i)当且仅当满足三个条件。a[i]<=a[j]。max(b[i])<=a[j]。a[i]<=min(b[j])。把a[i]也当作b[i],则要满足max(b[i])<=a[j]。a[i]<=min(b[j])。我们可以O(n^2)地dp。
其实我们只用满足两个关键字都小于或等于当前两个关键字就可以转移,我们考虑线段树套线段树。外层线段树代表第一关键字,内层代表第二关键字,把f值放进去,单点修改,区间查询就可以了。
详细点就是外层的每个区间[l,r]都拥有一颗关于第二关键字的线段树,每个包含第一关键字的[l,r]都需要按第二关键字在自己的线段树上插入f值。再详细就是看代码了。
其实这题可以用cdq分治,或k-d tree,或其他树套树来做。
code
#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)using namespace std;int const maxn=100000;int n,m,pon=1,a[maxn+10],mx[maxn+10],mi[maxn+10],son[maxn*108+10][3];void change2(int now,int l,int r,int mxi,int fi){ int m=(l+r)/2; son[now][2]=max(son[now][2],fi); if(l==r)return; else if(mxi<=m){ if(!son[now][0])son[now][0]=++pon; change2(son[now][0],l,m,mxi,fi); }else{ if(!son[now][1])son[now][1]=++pon; change2(son[now][1],m+1,r,mxi,fi); }}void change(int now,int l,int r,int ai,int mxi,int fi){ int m=(l+r)/2; if(!son[now][2])son[now][2]=++pon; change2(son[now][2],1,maxn+1,mxi,fi); if(l==r)return; else if(ai<=m){ if(!son[now][0])son[now][0]=++pon; change(son[now][0],l,m,ai,mxi,fi); }else{ if(!son[now][1])son[now][1]=++pon; change(son[now][1],m+1,r,ai,mxi,fi); }}int get2(int now,int l,int r,int a0,int ai){ int m=(l+r)/2; if((l==a0)&&(r==ai))return son[now][2]; else if(ai<=m){ if(!son[now][0])return 0; return get2(son[now][0],l,m,a0,ai); }else{ int tmp=0; if(son[now][1])tmp=get2(son[now][1],m+1,r,m+1,ai); if(son[now][0])tmp=max(tmp,son[son[now][0]][2]); return tmp; }}int get(int now,int l,int r,int mi0,int mii,int a0,int ai){ int m=(l+r)/2; if((l==mi0)&&(r==mii)){ if(!son[now][2])return 0; return get2(son[now][2],1,maxn+1,a0,ai); } else if(mii<=m){ if(!son[now][0])return 0; return get(son[now][0],l,m,mi0,mii,a0,ai); }else{ int tmp=0; if(son[now][1])tmp=get(son[now][1],m+1,r,m+1,mii,a0,ai); if(son[now][0]&&son[son[now][0]][2])tmp=max(tmp,get2(son[son[now][0]][2],1,maxn+1,a0,ai)); return tmp; }}int main(){ //freopen("len.in","r",stdin); //freopen("len.out","w",stdout); freopen("d.in","r",stdin); freopen("d.out","w",stdout); scanf("%d%d",&n,&m); fo(i,1,n)scanf("%d",&a[i]),a[i]++,mx[i]=mi[i]=a[i]; fo(i,1,m){ int x,y;scanf("%d%d",&x,&y);y++; mx[x]=max(mx[x],y); mi[x]=min(mi[x],y); } int ans=1; change(1,1,maxn+1,1,1,0); fo(i,1,n){ int f; ans=max(ans,f=get(1,1,maxn+1,1,mi[i],1,a[i])+1); change(1,1,maxn+1,a[i],mx[i],f); } printf("%d",ans); return 0;}
0 0
- 【bzoj4553】【Tjoi2016】【Heoi2016】【序列】【树套树】【线段树套线段树】
- BZOJ 4553 [Tjoi2016&Heoi2016]序列 线段树套treap
- [ 线段树套treap ] [ TJOI2016&&HEOI2016 ] BZOJ4552
- BZOJ4553 [Tjoi2016&Heoi2016]序列
- bzoj4553【TJOI2016&HEOI2016】序列
- BZOJ4553: [Tjoi2016&Heoi2016]序列
- 【bzoj4553】[Tjoi2016&Heoi2016]序列
- Bzoj4553: Tjoi2016&Heoi2016-序列
- 【bzoj4551】【Tjoi2016】【Heoi2016】【树】【线段树】
- 【bzoj4552】【Tjoi2016&Heoi2016】【排序】【线段树】
- BZOJ4552: [Tjoi2016&Heoi2016]排序 线段树
- [BZOJ4552][Tjoi2016&Heoi2016][线段树][二分]排序
- TJOI2016&HEOI2016 排序 线段树+二分答案
- [BZOJ4552][TJOI2016&HEOI2016]排序-线段树合并
- bzoj4552 [ TJOI2016 && HEOI2016 ] -- 二分+线段树
- [bzoj4552][Tjoi2016&Heoi2016]排序 二分+线段树
- [bzoj4552][Tjoi2016&Heoi2016]排序-二分+线段树
- [BZOJ4553][Tjoi2016&Heoi2016]序列 CDQ分治
- 黑马程序员_Java基础_我的Day13学习笔记
- python中执行shell命令的几种方式
- 用react+redux编写一个页面小demo
- 用JDK自带的包来解析XML文件(DOM+xpath)
- Hibernate4注解方法
- 【bzoj4553】【Tjoi2016】【Heoi2016】【序列】【树套树】【线段树套线段树】
- 进程的虚拟地址空间划分
- [深入理解Android卷二 全文-第四章]深入理解PackageManagerService
- 系统限流实践 - 接入层限流(上)
- contacts(通讯录)数据库
- PowerDesigner和Navicat for mysql的基础使用心得
- java打印二维数组
- Perl语言学习(Perl安装+编辑第一个程序)
- 关闭 linux下的umask( )函数、setsid( )函数