[BZOJ4553][HEOI2016]序列 CDQ分治
2017-07-22 15:20
417 查看
4553: [Tjoi2016&Heoi2016]序列
Time Limit: 20 Sec Memory Limit: 128 MBDescription
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你
,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可
。注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 31 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:3 3 33 2 3选择子序列
为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求
Input
输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。所有数字均为正整数
,且小于等于100,000
Output
输出一个整数,表示对应的答案Sample Input
3 41 2 3
1 2
2 3
2 1
3 4
Sample Output
3题解:
我们来分析一下这道题让我们干什么:
我们知道了一个序列,其中每一个元素都可能变化,
我们设他的原始值为a[i],最大值为maxv[i],最小值为minv[i],
再设f[i]为以i为结尾的最长符合要求子序列,显然这可以用一个dp来解决:对于f[i],有
f[i]=max{f[j]}+1
而对j的要求,由于同时只有一个元素发生变化,我们就要求满足
j<i&&maxv[j]<=a[i]&&a[j]<=minv[i]
我们发现,这好像长得“很像”一个三维偏序问题。
如果我们用树套树来解决的话,也不是不可以(详见勇士的战斗记录:BZOJ4553: [Tjoi2016&Heoi2016]序列 树套树优化DP)
但是为什么我们不用更简单的做法来解决呢?
显然,这个东西是可以用cdq分治来解决的
我们对于区间[l,r],如果这个元素i在mi前面,我们就用(maxv[i],a[i])作为他的权值;否则,就用(a[i],minv[i])来作为他的权值。
这样,就可以实现上面的想法了:用前面来更新后面。这也是本题的关键。
想到了这一点,代码实现就很简单了。代码见下:
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; const int N=300000; int n,m,bit[N+100],f[N+100]; struct num{int val,maxv,minv;}x[N+100]; struct cdq{int x,y,id;}a[N+100]; inline int lowbit(int a){return a&(-a);} inline bool mt(const cdq &a,const cdq &b) {return (a.x==b.x)?a.id<b.id:a.x<b.x;} inline void add(int i,int val) { while(i<=N) { bit[i]=(val==0)?0:max(bit[i],val); i+=lowbit(i); } } inline int sum(int i) { int ret=0; while(i) ret=max(ret,bit[i]),i-=lowbit(i); return ret; } void cdq(int l,int r) { if(l==r){f[l]=max(f[l],1);return;} int mi=(l+r)>>1; cdq(l,mi); for(int i=l;i<=r;i++) { if(i<=mi)a[i].x=x[i].val,a[i].y=x[i].maxv; else a[i].x=x[i].minv,a[i].y=x[i].val; a[i].id=i; } sort(a+l,a+r+1,mt); for(int i=l;i<=r;i++) { if(a[i].id<=mi)add(a[i].y,f[a[i].id]); else f[a[i].id]=max(sum(a[i].y)+1,f[a[i].id]); } for(int i=l;i<=r;i++)add(a[i].y,0); cdq(mi+1,r); } int main() { scanf("%d%d",&n,&m);int u,v,ans=0; for(int i=1;i<=n;i++) scanf("%d",&x[i].val),x[i].minv=x[i].maxv=x[i].val; while(m--) { scanf("%d%d",&u,&v); x[u].maxv=max(x[u].maxv,v); x[u].minv=min(x[u].minv,v); } cdq(1,n); for(int i=1;i<=n;i++)ans=max(ans,f[i]); printf("%d\n",ans); }
相关文章推荐
- 【bzoj4553】【Tjoi2016】【Heoi2016】【序列】【树套树】【线段树套线段树】
- 【BZOJ4553】【TJOI2016】【HEOI2016】序列
- [bzoj4553][Tjoi2016&Heoi2016]序列 cdq分治
- BZOJ 4553 [Tjoi2016&Heoi2016]序列 ——CDQ分治 树状数组
- 【bzoj4553】【TJOI2016&HEOI2016】【序列】【cdq分治+树状数组】
- [BZOJ4553][TJOI2016&&HEOI2016]序列(CDQ分治)
- [DP][CDQ分治] BZOJ 4553: [Tjoi2016&Heoi2016]序列
- BZOJ 4553 HEOI 2016 seq
- [BZOJ3963][WF2011][CDQ分治][斜率优化][DP]MachineWorks
- JZOJ4559 【NOI2016模拟6.23】水平线上的肮脏交易和卑鄙勾当 转换模型后CDQ分治
- bzoj2961 共点圆(cdq分治维护凸包,计算几何)
- BZOJ 2683 CDQ分治
- bzoj2683 简单题 (cdq分治 + 树状数组)
- BZOJ 4542([Hnoi2016]序列-莫队)
- 【HNOI2016】【BZOJ4540】序列
- BZOJ 1176 Mokia(CDQ分治)
- bzoj 3262: 陌上花开 【cdq分治】
- 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治
- bzoj 3672 利用点分治将CDQ分治推广到树型结构上
- bzoj3295 [Cqoi2011]动态逆序对(CDQ分治)