算法复习——cdq分治
Posted AseanA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法复习——cdq分治相关的知识,希望对你有一定的参考价值。
题目:
Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
Input
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。
以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性
Output
包含N行,分别表示评级为0...N-1的每级花的数量。
Sample Input
10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
Sample Output
3
1
3
0
1
0
1
0
0
1
1
3
0
1
0
1
0
0
1
HINT
1 <= N <= 100,000, 1 <= K <= 200,000
Source
题解:
CDQ分治解三维偏序的模板题,以下是关于cdq分治的大概介绍
CDQ的核心就是分为左右两组后,算左边对右边的贡献····
但CDQ分治运用最广泛的是解决偏序的问题···比如上面的陌上花开就是解决关于(a,b,c)的三维偏序问题····
解决这类问题的核心是降维···一个一个忽略每一维影响···比如这道题,先以a优先排序,从而只用管b和c···然后在分成左右两组时每组以b优先排序··进而最后利用树状数组解决c
详细见:http://www.cnblogs.com/mlystdcall/p/6219421.html
不得不说真神奇·····
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=1e5+5; const int M=2e5+5; inline int R() { char c;int f=0,i=1; for(c=getchar();(c<\'0\'||c>\'9\')&&c!=\'-\';c=getchar()); if(c==\'-\') i=-1,c=getchar(); for(;c<=\'9\'&&c>=\'0\';c=getchar()) f=(f<<3)+(f<<1)+c-\'0\'; return f*i; } struct node { int x,y,z,cnt,ans; }f[N],a[N]; bool cmp(node a,node b) { if(a.x==b.x&&a.y==b.y) return a.z<b.z; else if(a.x==b.x) return a.y<b.y; else return a.x<b.x; } int m,n,k,tot,tree[M],ans[N]; inline bool operator < (node a,node b) { if(a.y==b.y) return a.z<b.z; else return a.y<b.y; } inline void insert(int u,int w) { for(int i=u;i<=k;i+=(i&(-i))) tree[i]+=w; } inline int query(int u) { int temp=0; for(int i=u;i>0;i-=(i&(-i))) temp+=tree[i]; return temp; } inline void solve(int l,int r) { if(l==r) return; int mid=(l+r)/2,i,j; solve(l,mid),solve(mid+1,r); sort(a+l,a+mid+1);sort(a+mid+1,a+r+1); i=l,j=mid+1; while(j<=r) { while(i<=mid&&a[i].y<=a[j].y) { insert(a[i].z,a[i].cnt);i++; } a[j].ans+=query(a[j].z);j++; } for(j=l;j<i;j++) insert(a[j].z,-a[j].cnt); } int main() { //freopen("a.in","r",stdin); m=R(),k=R(); for(int i=1;i<=m;i++) { f[i].x=R();f[i].y=R();f[i].z=R(); } sort(f+1,f+m+1,cmp); a[++n]=f[1];tot=1; a[1].cnt=1; for(int i=2;i<=m;i++) { if(f[i].x!=f[i-1].x||f[i].y!=f[i-1].y||f[i].z!=f[i-1].z) ++n,tot=1; else tot++; a[n]=f[i],a[n].cnt=tot; } solve(1,n); for(int i=1;i<=n;i++) ans[a[i].ans+a[i].cnt-1]+=a[i].cnt; for(int i=0;i<m;i++) printf("%d\\n",ans[i]); return 0; }
以上是关于算法复习——cdq分治的主要内容,如果未能解决你的问题,请参考以下文章