bzoj 3262 陌上花开
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3262
CDQ裸题。三维偏序。一眼看出一维排序、一维递归、一维树状数组。
可是有相等的怎么办?
然后看了TJ。https://blog.csdn.net/creationaugust/article/details/48788317
https://blog.csdn.net/clove_unique/article/details/54235339
其实分析一下:c的相等在树状数组里自己就能弄了;
仅a相等:一开始排序的第二关键字是b,然后就没事了(递归中可以解决);
仅b相等:毫无关系;
a和b都相等:一开始排序的第二关键字是b的话,想一想发现只有最大的那个包含了所有,所以最后弄一弄就行了;
或从一开始就找出所有a、b、c都相等的东西,记一个num。
注意树状数组的边界是m!!!
*先递归下去,再做本层的操作,本层的排序就不会对递归下去的东西造成影响。(当然也可以把本层的东西拿出来到别的数组里,对那个数组排序、操作)
需要保证的是本层默认的:至少是mid左边的a一定小于mid右边的a。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5,M=2e5+5; int n,m,f[M],cnt[N],tot; struct Node{ int a,b,c,sum,num; }t[N],s[N]; bool cmpb(Node x,Node y){return x.b<y.b;} bool cmp(Node x,Node y){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);} bool check(Node x,Node y){return x.a==y.a&&x.b==y.b&&x.c==y.c;} void add(int x,int v){for(;x<=m;x+=(x&-x))f[x]+=v;} //x<=m!!!!!!!!!!!! int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;} void cdq(int l,int r) { if(l==r)return; int mid=((l+r)>>1),p=l; cdq(l,mid);cdq(mid+1,r); sort(t+l,t+mid+1,cmpb);sort(t+mid+1,t+r+1,cmpb); //sort左开右闭 for(int i=mid+1;i<=r;i++) { while(p<=mid&&t[p].b<=t[i].b)add(t[p].c,t[p].num),p++; //p<=mid!!! //请不要把p++写在add里面 t[i].sum+=query(t[i].c); } for(int i=l;i<p;i++)add(t[i].c,-t[i].num); //撤销 // sort(t+l,t+mid+1,cmpa);sort(t+mid+1,t+r+1,cmpa); //撤销 } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].c); sort(s+1,s+n+1,cmp);int ct; for(int i=1;i<=n;i++) { ct=1; while(check(s[i],s[i+1]))ct++,i++; t[++tot]=s[i];t[tot].num=ct; } cdq(1,tot); for(int i=1;i<=tot;i++)cnt[t[i].sum+t[i].num-1]+=t[i].num; for(int i=0;i<n;i++)printf("%d\n",cnt[i]); return 0; }
当然也可以先做完本层的,再排序回去。不过会很慢。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5,M=2e5+5; int n,m,f[M],cnt[N]; struct Node{ int a,b,c,sum,num; }t[N]; bool cmpb(Node x,Node y){return x.b<y.b;} bool cmp(Node x,Node y){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);} bool check(Node x,Node y){return x.a==y.a&&x.b==y.b&&x.c==y.c;} void add(int x,int v){for(;x<=m;x+=(x&-x))f[x]+=v;} //x<=m!!!!!!!!!!!! int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;} void cdq(int l,int r) { if(l==r)return; int mid=((l+r)>>1),p=l; sort(t+l,t+mid+1,cmpb);sort(t+mid+1,t+r+1,cmpb); //sort左开右闭 for(int i=mid+1;i<=r;i++) { while(p<=mid&&t[p].b<=t[i].b)add(t[p].c,1),p++; //p<=mid!!! //请不要把p++写在add里面 t[i].sum+=query(t[i].c); } for(int i=l;i<p;i++)add(t[i].c,-1); //撤销 sort(t+l,t+mid+1,cmp);sort(t+mid+1,t+r+1,cmp); //撤销 cdq(l,mid);cdq(mid+1,r); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c); sort(t+1,t+n+1,cmp);int ct; cdq(1,n); for(int i=1;i<=n;i++) { ct=1; while(check(t[i],t[i+1]))ct++,i++; cnt[t[i].sum]+=ct; } for(int i=0;i<n;i++)printf("%d\n",cnt[i]); return 0; }
十分奇怪的是为什么不记num,然后弄先递归下去的版本,就WA了?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5,M=2e5+5; int n,m,f[M],cnt[N]; struct Node{ int a,b,c,sum,num; }t[N]; bool cmpb(Node x,Node y){return x.b<y.b;} bool cmp(Node x,Node y){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);} bool check(Node x,Node y){return x.a==y.a&&x.b==y.b&&x.c==y.c;} void add(int x,int v){for(;x<=m;x+=(x&-x))f[x]+=v;} //x<=m!!!!!!!!!!!! int query(int x){int ret=0;for(;x;x-=(x&-x))ret+=f[x];return ret;} void cdq(int l,int r) { if(l==r)return; int mid=((l+r)>>1),p=l; cdq(l,mid);cdq(mid+1,r); sort(t+l,t+mid+1,cmpb);sort(t+mid+1,t+r+1,cmpb); //sort左开右闭 for(int i=mid+1;i<=r;i++) { while(p<=mid&&t[p].b<=t[i].b)add(t[p].c,1),p++; //p<=mid!!! //请不要把p++写在add里面 t[i].sum+=query(t[i].c); } for(int i=l;i<p;i++)add(t[i].c,-1); //撤销 // sort(t+l,t+mid+1,cmp);sort(t+mid+1,t+r+1,cmp); //撤销 } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%d",&t[i].a,&t[i].b,&t[i].c); sort(t+1,t+n+1,cmp);int ct; cdq(1,n); sort(t+1,t+n+1,cmp);// for(int i=1;i<=n;i++) { ct=1; while(check(t[i],t[i+1]))ct++,i++; cnt[t[i].sum]+=ct; } for(int i=0;i<n;i++)printf("%d\n",cnt[i]); return 0; }
分类:
算法--CDQ分治
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
· SQL Server统计信息更新会被阻塞或引起会话阻塞吗?
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 本地部署 DeepSeek:小白也能轻松搞定!
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 普通人也能轻松掌握的20个DeepSeek高频提示词(2025版)