赶鸭子上架的cdq分治
Posted mxang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了赶鸭子上架的cdq分治相关的知识,希望对你有一定的参考价值。
前置技能:归并排序,树状数组。
cdq分治主要是用来离线解决一些奇怪的问题的。可以用来代替一些高级数据结构比如树套树或者KD-Tree之类的。。。
话说挑战2上的KD-Tree我到现在还没开始学。。。
cdq遇到在线的好像就死掉了?(雾
目前在博主的能力范围内:
主要用来解决多维(三维)偏序问题。
bzoj 陌上花开:给n朵花,每朵花有abc三个属性,问对于每朵花 i 满足 ai>=aj&&bi>=bj&&ci>=cj的花儿有多少。
我们使用cdq减掉一维同时复杂度乘以log。
回想归排求逆序对,其实也就是二维偏序问题,我们在对x排好序的前提下,x可以当成下标,求 xi<xj&&yi>yj的数的数目。
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n,a[500005],b[500005];ll ans; void cdq(int l,int r){ if(l==r) return; int m=l+r>>1; cdq(l,m); cdq(m+1,r); int i=l,j=m+1,st=l; while (i<=m&&j<=r){ if(a[i]<=a[j]){ b[st++]=a[i++]; } else{ ans+=(m-i+1); b[st++]=a[j++]; } } while (i<=m) b[st++]=a[i++]; while (j<=r) b[st++]=a[j++]; for(int i=l;i<=r;i++){ a[i]=b[i]; } } int main(){ ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; cdq(1,n); cout<<ans<<endl; }
然后维护左区间对右区间每个数的影响,也就是 ans+=(m-i+1);这句话。
那么我们知道bit也可以解决二维偏序问题,所以我们使用 归并+bit就可以解决三维偏序问题。
关键代码处加了注释
#include <bits/stdc++.h> using namespace std; const int N = 2e5+5; struct Flower{ int a,b,c,cnt,ans; }a[N],A[N]; bool cmp2(const Flower &a, const Flower&b){ return a.a<b.a||(a.a==b.a&&a.b<b.b)||(a.a==b.a&&a.b==b.b&&a.c<b.c); } bool cmp1(const Flower& a,const Flower& b){ return a.b<b.b||(a.b==b.b&&a.c<b.c); } int n,k,c[N]; int lowbit(int k){ return k&-k;} void add(int pos,int num){ while (pos<=k){ c[pos]+=num;pos+=lowbit(pos); } } int sum(int x){ int ans = 0; while (x){ ans+=c[x];x-=lowbit(x); } return ans; } Flower t[N]; void cdq(int l,int r){//l-r满足a非严格递增 if(l==r) return; int m = l+r>>1; cdq(l,m); cdq(m+1,r); int j=l; for(int i=m+1;i<=r;i++){ for(;j<=m&&A[j].b<=A[i].b;j++) add(A[j].c,A[j].cnt); A[i].ans+=sum(A[i].c); } for(int i=l;i<j;i++) add(A[i].c,-A[i].cnt); int l1=l,l2=m+1; int pos=l; while(l1<=m||l2<=r) { if(l2>r||(l1<=m&&cmp1(A[l1],A[l2]))) t[pos++]=A[l1++]; else t[pos++]=A[l2++]; } for(int i=l;i<=r;i++) A[i]=t[i]; } int ans[N]; int main(){ ios::sync_with_stdio(false); cin>>n>>k; for(int i=1;i<=n;i++){ cin>>a[i].a>>a[i].b>>a[i].c; a[i].cnt=1; } sort(a+1,a+1+n,cmp2);//先保证a的大小关系 int cnt = 1; for(int i=1;i<=n;i++){ if(i==1||!(a[i].a==a[i-1].a&&a[i].b==a[i-1].b&&a[i].c==a[i - 1].c))//处理abc三个属性全部一样的花 A[cnt++] = a[i]; else A[cnt-1].cnt++; } cdq(1,cnt-1); for(int i = 1; i <= cnt; i++) ans[A[i].ans+A[i].cnt-1] += A[i].cnt; for(int i = 0; i < n; i++) cout<<ans[i]<<endl; return 0; } /** 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 1 3 0 1 0 1 0 0 1 */
SHOI2007 园丁的烦恼
做法很多。。。这里讲一下cdq。和上一道题是一样的吧,可以这样想,把 t,x,y当成三个变量,t代表了操作时间,可以理解成 查询/添加,
然后对于 (x1,y1)到(x2,y2)可以差分一下,en...
那么这道题就变成了一个 求 满足 ti>tj,xi>=xj,yi>=yi 这样的一个三维偏序问题
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 35e5+5; 5 struct Node{ 6 int op,x,y,w,id; 7 }a[N],A[N]; 8 int n,m,up,tot; 9 int c[N]; 10 int lowbit(int x){ 11 return x&-x; 12 } 13 void upd(int pos,int x){ 14 while (pos<=up) { 15 c[pos]+=x; 16 pos+=lowbit(pos); 17 } 18 } 19 int sum(int x){ 20 int res = 0; 21 while (x){ 22 res+=c[x]; 23 x-=lowbit(x); 24 } 25 return res; 26 } 27 void clear(int x){ 28 while(x<=up) { 29 if(c[x]) c[x]=0; 30 else break; 31 x+=lowbit(x); 32 } 33 } 34 bool cmp(Node a,Node b){ 35 return a.x<b.x||(a.x==b.x&&a.op<b.op); 36 } 37 int ans[N]; 38 void cdq(int l,int r){ 39 if(l==r) return; 40 int mid = l+r>>1; 41 cdq(l,mid); 42 cdq(mid+1,r); 43 int i=l,j=mid+1,st=l; 44 while (i<=mid&&j<=r){ 45 if(cmp(a[i],a[j])){ 46 if(a[i].op==0) 47 upd(a[i].y,1); 48 A[st++]=a[i++]; 49 } else{ 50 if(a[j].op==1) 51 ans[a[j].id]+=a[j].w*sum(a[j].y); 52 A[st++]=a[j++]; 53 } 54 } 55 while (i<=mid) A[st++]=a[i++]; 56 while (j<=r){ 57 if(a[j].op==1) 58 ans[a[j].id]+=a[j].w*sum(a[j].y); 59 A[st++] = a[j++]; 60 } 61 for(int i=l;i<=r;i++){ 62 clear(a[i].y); 63 a[i]=A[i]; 64 } 65 } 66 void ins(int op,int x,int y,int w,int id){ 67 tot++; 68 a[tot].op=op;a[tot].x=x;a[tot].y=y;a[tot].w=w;a[tot].id=id; 69 } 70 int main(){ 71 scanf("%d%d",&n,&m); 72 int x,y; 73 for(int i=1;i<=n;i++){ 74 scanf("%d%d",&x,&y);;x++;y++; 75 ins(0,x,y,0,0); 76 up = max(y,up); 77 } 78 int x2,y2; 79 for(int i=1;i<=m;i++){ 80 scanf("%d%d%d%d",&x,&y,&x2,&y2); 81 x++;y++;x2++;y2++; 82 ins(1,x2,y2,1,i); 83 ins(1,x-1,y2,-1,i); 84 ins(1,x2,y-1,-1,i); 85 ins(1,x-1,y-1,1,i); 86 up = max(max(y,y2),up); 87 } 88 cdq(1,tot); 89 for(int i=1;i<=m;i++) 90 printf("%d ",ans[i]); 91 return 0; 92 }
以上是关于赶鸭子上架的cdq分治的主要内容,如果未能解决你的问题,请参考以下文章