赶鸭子上架的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; }
View Code
然后维护左区间对右区间每个数的影响,也就是 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];elseA[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\n",ans[i]); 91 return 0; 92 }
bzoj 3295 动态逆序对
这类问题我们有一个方法就是倒着来一遍吧。然后我们按照时间戳给所有元素标号,每个点 具有 t,x,y 三个属性,就又变成了一个三维偏序问题。
那么我们需要求的 就是 满足(令当前元素为i) t<ti,x<xi,y>yi的数目加上 t<ti, x>xi,y<yi的数目。
然后我们在归并的时候分别从左往右扫,从右往左扫一下就可以了。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5+5; 4 struct Node{ 5 int t,x,y; 6 }a[N],A[N]; 7 int ld[N],yx[N]; 8 int n,m,c[N]; 9 int lowbit(int x){ return x&-x;} 10 void upd(int pos,int x){ 11 while (pos<=n){ 12 c[pos]+=x; 13 pos+=lowbit(pos); 14 } 15 } 16 void clear(int x){ 17 while (x<=n){ 18 if(c[x]) c[x]=0,x+=lowbit(x); 19 else break; 20 } 21 } 22 int sum(int x){ 23 int res = 0; 24 while (x){ 25 res+=c[x]; 26 x-=lowbit(x); 27 } 28 return res; 29 } 30 void cdq(int l,int r){//保证x单调增 31 if(l==r) return; 32 int mid = l+r>>1; 33 int s1=l,s2=mid+1; 34 for(int i=l;i<=r;i++){//左边的t全部小于右边的,同时x单调 35 if(a[i].t<=mid) 36 A[s1++]=a[i]; 37 else 38 A[s2++]=a[i]; 39 } 40 for(int i=l;i<=r;i++) 41 a[i]=A[i]; 42 s1=l;s2=mid+1; 43 while (s2<=r){// 44 while (s1<=mid&&a[s1].x<a[s2].x){//x小y大 45 upd(a[s1].y,1);s1++; 46 } 47 ld[a[s2].t]+=(s1-l)-sum(a[s2].y);//左边y比他大的 48 s2++; 49 } 50 for(int i=l;i<=mid;i++) 51 clear(a[i].y); 52 s1=mid;s2=r; 53 while (s2>=mid+1){ 54 while (s1>=l&&a[s1].x>a[s2].x){//x大y小 55 upd(a[s1].y,1); 56 --s1; 57 } 58 yx[a[s2].t]+=sum(a[s2].y-1); 59 s2--; 60 } 61 for(int i=l;i<=mid;i++) 62 clear(a[i].y); 63 cdq(l,mid);cdq(mid+1,r); 64 } 65 int pos[N]; 66 long long ans[N]; 67 int main(){ 68 ios::sync_with_stdio(false); 69 cin>>n>>m; 70 for(int i=1;i<=n;i++){ 71 cin>>a[i].y;a[i].x=i;pos[a[i].y]=i; 72 } 73 int x,all=n; 74 for(int i=1;i<=m;i++){ 75 cin>>x; 76 a[pos[x]].t=all--; 77 } 78 for(int i=1;i<=n;i++){ 79 if(!a[i].t) 80 a[i].t=all--;// 81 } 82 cdq(1,n); 83 for(int i=1;i<=n;i++){ 84 ans[i]=ans[i-1]+yx[i]+ld[i]; 85 } 86 for(int i=n;i>=n-m+1;i--){ 87 cout<<ans[i]<<endl; 88 } 89 }
View Code
转载于:https://www.cnblogs.com/MXang/p/10029899.html
赶鸭子上架的cdq分治相关推荐
- 【BZOJ-3456】城市规划 CDQ分治 + NTT
题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=3456 Solution 这个问题可以考虑dp,利用补集思想 N个点的简单图总数量为$2^{ ...
- BZOJ 1176: [Balkan2007]Mokia( CDQ分治 + 树状数组 )
考虑cdq分治, 对于[l, r)递归[l, m), [m, r); 然后计算[l, m)的操作对[m, r)中询问的影响就可以了. 具体就是差分答案+排序+离散化然后树状数组维护.操作数为M的话时间 ...
- bzoj2961 共点圆 (CDQ分治, 凸包)
/* 可以发现可行的圆心相对于我们要查询的点是在一个半平面上, 然后我们要做的就是动态维护凸壳然后用这个半平面去切它 看看是否是在合法的那一面然后cdq分治就可以了代码基本是抄的,*/#include ...
- 洛谷P3122 [USACO15FEB]圈住牛Fencing the Herd(计算几何+CDQ分治)
题面 传送门 题解 题目转化一下就是所有点都在直线\(Ax+By-C=0\)的同一侧,也就可以看做所有点代入\(Ax+By-C\)之后的值符号相同,我们只要维护每一个点代入直线之后的最大值和最小值,看 ...
- 【BZOJ3963】[WF2011]MachineWorks cdq分治+斜率优化
[BZOJ3963][WF2011]MachineWorks Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先 ...
- CDQ分治 + 树状数组 ---- C. Goodbye Souvenir(三维偏序+思维)
题目链接 题目大意: 给定长度为nnn的数组, 定义数字XXX在[l,r][l,r][l,r]内的值为数字XXX在[l,r][l,r][l,r]内最后一次出现位置的下标减去第一次出现位置的下标 给定m ...
- [学习笔记]CDQ分治
分治,考虑前一半对后一半的影响. (和一般分治不太相同的思想是,一般分治不分谁对谁的影响,跨mid的都要统计.(全局变量统计) 而CDQ貌似要落脚到前一半对后一半的影响上,也就是贡献在后一半统计,由前 ...
- BZOJ 1492: [NOI2007]货币兑换Cash [CDQ分治 斜率优化DP]
传送门 题意:不想写... 扔链接就跑 好吧我回来了 首先发现每次兑换一定是全部兑换,因为你兑换说明有利可图,是为了后面的某一天两种卷的汇率差别明显而兑换 那么一定拿全利啊,一定比多天的组合好 $f[ ...
- 【教程】简易CDQ分治教程学习笔记
前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦! CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...
最新文章
- Android支付接入(五):机锋网
- 服务器中同一个【ip:port】可以多次accept的问题
- Kafka解惑之Old Producer(2)——Sync Analysis
- SAP C4C里前台Opportunity搜索的响应明细
- 用Cocos2dx开发棋牌游戏的观点解析
- 决胜蓝桥杯python组-集合、字典
- 安装Oracle 11g 出现交换空间不够
- 课时46:魔法方法:描述符(property的原理)
- RK3568开发笔记-buildroot移远EC20模块调试记录
- 应用安全测试技术DAST、SAST、IAST对比分析-持续更新
- MacOS上如何将MOV文件转换为MP4
- 评估分形指数和HURST指数预测金融时间序列的能力
- IEEE Transactions on Mobile Computing -TMC
- 201704 创建财务凭证函数
- 手机软件测试规范(含具体用例)
- Java基础学习九 多线程
- MarkdownPad2 自动生成目录
- 西安交通大学大学计算机考试题,西安交通大学17年3月课程考试《计算机应用基础》作业考核试题...
- [书籍分享]0-009.微信营销与运营解密:利用微信创造商业价值的奥秘
- html输入框的属性,文本框以及input的属性及功能