算法复习——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

Sample Output

3
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分治的主要内容,如果未能解决你的问题,请参考以下文章

算法CDQ分治初探

CDQ分治小结

模板:CDQ分治

CDQ 分治算法模板

CDQ分治与整体二分

BZOJ 3262: 陌上花开 cdq分治 树状数组