三维偏序 CDQ
来源:互联网 发布:张宴 nginx 编辑:程序博客网 时间:2024/05/01 02:23
来看这样一道题
(bzoj陌上百合)
描述:
给出 n 个点(x,y,z),请找出最长上升子序列,即对于选择序列中的 i<j,
xi<=xj,yi<=yj,zi<=zj。
输出最长上升子序列的长度和方案数。
输入:
第一行包含一个整数 n
接下来 n 行,每行有 3 个整数 xi,yi,zi
输出:
输出长度和方案数(方案数对2^30取mod)
输入输出样例:
cdq.in cdq.out
3
2 0 0
0 1 1
0 1 0
2 1
5
3 0 0
0 1 0
0 0 1
0 2 2
3 3 3
3 2
数据范围:
x,y,z<=1000000000
对于 20%数据 n<=1000
对于 100%数据 n<=100000
这就是经典的3维偏序.
三维偏序是可以对点排序之后求的
首先看二维偏序:(x,y)
如果我们对x排序,那么就转化成求y的lis
同理,我们也需要一些转化.
按照cdq分治基本思想,一维排序,二维分治,三维树状数组(数据结构)
-----------------------------------------------------------------------------------------------
接下来就以这道题为例,浅谈cdq分治思想
假设我们按第一维的坐标排好序了,我们就需要在x排好序的点对(y,z)中找二维偏序.
因为之前已经排过序(x)了,所以直接再排序是有一点问题的,在这里可以写树套树维护.
树套树的码量有点大,而且不太好写,所以就不谈了。
谈点实际的:
我们已经对x这一维排好序了,那么我们将[l,r]的点对分成两个区间[l,mid] 和 [mid+1,r]
然后依次递归调用,先处理[l,mid]的信息,然后处理[l,mid]对[mid+1,r]的影响,最后处理[mid+1,r]的信息
(为什么要这样?因为这道题是求三维lis,左边的区间会对右边的产生影响.)
继续刚才的分治:如果我们得到了两个区间的信息,就可以对第3维维护信息了。
可能有些不懂,下面讲一下具体的吧:
(下面是计算[l,mid]对[mid+1,r]的影响)
我们将2分的区间分别按y排序(因为第一维之前排过序,可以保证[mid+1,r]的所有x>=[l,mid]的x. 因为是考虑左区间对右区间的影响,所以就不用考虑区间内部信息)
而后第二位也是有序了的。
然后枚举[mid+1,r]每个元素,并且维护左区间的一个指针i,一旦当前枚举到的元素j的y,就把左区间所有i.y<=j.y的信息更新到树状数组里面去(我们保证了y的单调性,所以复杂度大致是 区间长*更新单次的时间)
树状数组用来干什么?我们枚举到右区间一个j,将左区间中所有i.y<=j.y(第一次排序保证了i.x<=j.x)的z在树状数组对应的位置的dp值更新为max(dp[i]). 所以树状数组是用来维护第3维的dp值
对于枚举到的j,更新了所有i.y<=j.y的i的信息之后dp[j]=query([1,j.z])(这一段区间的最大dp值)+1;
然后把所有dp值求max就得到了答案1
那么怎么求方案呢?
我其实也很迷茫,不过参考了各种资料后,发现只需要再维护一个数组保存方案数即可.
在更新dp值的时候,if(dp[j]<getmax(1,j.z).dp)dp[j]=getmax(1,j.z).dp,更新方案数cnt[j]=getmax(1,j.z).cnt;
if(dp[j]==getmax(1,j.z).dp)cnt[j]+=getmax(1,j.z).cnt;
就行了!
有不清楚的,再细想一下吧!
AC代码:
<span style="font-size:18px;">#include<cstdio>#include<algorithm>#include<queue>#include<cstring>#include<cstdlib>#include<iostream>#include<cmath>#include<ctime>#define LL long longconst LL M=1<<30;using namespace std;double st,ft;const int maxn=100000+20;struct xnode{int x,y,z,id;}q[maxn],tl[maxn],tr[maxn];int dp[maxn];LL c[maxn];int n;bool cmpx(xnode a,xnode b){if(a.x!=b.x)return a.x<b.x;if(a.y!=b.y)return a.y<b.y;return a.z<b.z;}bool cmpy(xnode a,xnode b){if(a.y!=b.y)return a.y<b.y;return a.z<b.z;}int det[maxn];int m;int cnt;int find(int x){return lower_bound(det+1,det+m+1,x)-det;}struct Ans{int dp;LL cnt;Ans(){dp=cnt=0;}};Ans f[maxn];void updata(int i,int x,LL v){while(i<=m){if(f[i].dp<x){f[i].dp=x;f[i].cnt=v%M;}else if(f[i].dp==x){f[i].cnt+=v;f[i].cnt%=M;}i+=(i&-i);}}void clear(int i){while(i<=m){f[i].dp=0;f[i].cnt=0;i+=(i&-i);}}Ans query(int i){Ans ans;while(i){if(ans.dp<f[i].dp){ans.dp=f[i].dp;ans.cnt=f[i].cnt%M;}else if(ans.dp==f[i].dp){ans.cnt+=f[i].cnt;ans.cnt%=M;}i-=(i&-i);}return ans;}void work(int l,int r){int mid=(l+r)>>1;int t1,t2;t1=t2=0;for(int i=l;i<=mid;i++)tl[++t1]=q[i];for(int i=mid+1;i<=r;i++)tr[++t2]=q[i];sort(tl+1,tl+t1+1,cmpy);sort(tr+1,tr+t2+1,cmpy);for(int i=1,j=1;j<=t2;j++){while(tl[i].y<=tr[j].y&&i<=t1){updata(tl[i].z,dp[tl[i].id],c[tl[i].id]);i++;}Ans sum=query(tr[j].z);sum.dp++;if(dp[tr[j].id]<sum.dp){dp[tr[j].id]=sum.dp;c[tr[j].id]=sum.cnt%M;}else if(dp[tr[j].id]==sum.dp){c[tr[j].id]+=sum.cnt;c[tr[j].id]%=M;}}for(int i=l;i<=mid;i++)clear(q[i].z);}void cal(int l,int r){if(l==r)return ;int mid=(l+r)>>1;cal(l,mid);work(l,r);cal(mid+1,r);}int main(){freopen("cdq.in","r",stdin);freopen("cdq.out","w",stdout);cnt=0;scanf("%d",&n);for(int i=1;i<=n;i++){q[i].id=i;dp[i]=1;c[i]=1;}for(int i=1;i<=n;i++){scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z);det[++cnt]=q[i].z;}sort(det+1,det+cnt+1);m=unique(det+1,det+cnt+1)-det-1;for(int i=1;i<=n;i++)q[i].z=find(q[i].z);sort(q+1,q+n+1,cmpx);cal(1,n);int ans=0;LL sum=0;for(int i=1;i<=n;i++){if(dp[i]>ans){ans=dp[i];sum=c[i]%M;}else if(dp[i]==ans){sum+=c[i];sum%=M;}}printf("%d %I64d\n",ans,sum);return 0;}</span>
- 三维偏序 CDQ
- 三维偏序 树套树&cdq分治
- CDQ分治--模板 BZOJ 3262--陌上花开【三维偏序】
- [bzoj3262]陌上花开 三维偏序 cdq分治+树状数组
- bzoj3262陌上花开 cdq分治 三维偏序
- 洛谷P3810(三维偏序,CDQ分治果题)
- HDU 5618 CDQ分治(三维偏序)
- NEU 1704 三维偏序(CDQ分治+树状数组)
- CDQ分治 陌上花开(三维偏序)
- SPOJ LIS2 Another Longest Increasing Subsequence Problem 三维偏序最长链 CDQ分治
- HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
- BZOJ 3262: 陌上花开 CDQ三维偏序,树套树,两种解法
- SPOJ LIS2 (Another Longest Increasing Subsequence Problem) CDQ求三维偏序+离散化+LIS
- SPOJ-LIS2 Another Longest Increasing Subsequence Problem 【三维偏序CDQ】
- 【BZOJ3295】动态逆序对(CQOI2011)-CDQ分治:三维偏序
- BZOJ 3262 陌上花开、HDU 5618 Jam's problem again(三维偏序、cdq分治 + BIT)
- CDQ分治和二维偏序
- 三维偏序
- [自考]计算机网络原理
- 程序员面试笔试宝典学习记录(一)(常见面试笔试题目)
- hdu 1151 Air Raid(最小路径覆盖)
- [BZOJ 4066]简单题
- npm package.json字段简介
- 三维偏序 CDQ
- 《数据结构与算法分析(c 描述)》—— 第四章笔记
- HBitmap、Bitmap、CBitmap之间的区别与联系
- Android问题集(七)——webview 使用问题三四个
- android从图库(gallery)选择一张图片
- CodeForces 630 J. Divisibility(数论)
- 【Linux 基础篇】之 Linux中的正则
- 1033. To Fill or Not to Fill (25)
- HDU1789贪心