【BZOJ3262】陌上花开 (CDQ分治+树状数组+排序)
Time Limit: 3000 ms Memory Limit: 256 MB
Description
有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),用三个整数表示。
现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。
定义一朵花A比另一朵花B要美丽,当且仅当 。
显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。
Input
第一行为 N,K 分别表示花的数量和最大属性值。
以下 N 行,每行三个整数 表示第i朵花的属性。
Output
包含 行,分别表示评级为 的每级花的数量。
Sample Input |
Sample Output |
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
|
题解
题目大意为,给定n个三元组,每个三元组的等级为小于等于它的三元组的个数。
其中“小于”定义为:对于两个三元组与,当且仅当且
且。
隐隐约约想到单调性的问题。
1. 对于,我们直接排序处理(按照第一,第二,第三的优先级排序);
2. 对于,开始使用CDQ分治瞎搞(其中每次回溯的时候分别对左右区间,以为第一关键字排序,为计算左区间对右区间的贡献作准备);
3. 对于:我们在CDQ分治时,已经确定左半边区间的是小于右半边区间的;这时采用双指针扫描,以右区间指针指向的三元组为基准三元组。考虑此时 是递增的,我们就将左区间的指针移到最靠右的三元组,使得这个三元组的值不超过基准三元组的值;
其中,我们一边扫描左区间一边将左区间扫过的三元组的值丢进树状数组里,左指针到基准时,直接询问树状数组内小于等于与基准三元组的值。
完全相同的几朵花怎么办? 我们按照上面提到的排序方法排序所有花,对于相同的花,将它们的等级都标记为相同花的中等级最高的即可。
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 const int N=1e5+10,K=2e5+10; 5 int n,k,ans[N]; 6 struct Flower{int s,c,m,sum;}f[N]; 7 struct Bit{ 8 int arr[K],lis[N],cnt; 9 void reset(){ 10 for(;cnt;cnt--) add(lis[cnt],-1,1); 11 } 12 void add(int u,int num,int flag){ 13 if(!u) return; 14 if(!flag) 15 lis[++cnt]=u; 16 for(;u<=k;u+=u&-u) arr[u]+=num; 17 } 18 int que(int u){ 19 int ret=0; 20 for(;u;u-=u&-u) ret+=arr[u]; 21 return ret; 22 } 23 }bit; 24 bool cmpAll(Flower x,Flower y){ 25 if(x.s!=y.s) return x.s<y.s; 26 if(x.c!=y.c) return x.c<y.c; 27 return x.m<y.m; 28 } 29 bool cmpC(Flower x,Flower y){return x.c<y.c;} 30 void cdq(int l,int r){ 31 if(l==r) return; 32 int mid=(l+r)/2; 33 cdq(l,mid); 34 cdq(mid+1,r); 35 sort(f+l,f+mid+1,cmpC); 36 sort(f+mid+1,f+r+1,cmpC); 37 int i=l,j; 38 bit.reset(); 39 for(i=l,j=mid+1;j<=r;j++){ 40 while(i<=mid&&f[i].c<=f[j].c){ 41 bit.add(f[i].m,1,0); 42 i++; 43 } 44 f[j].sum+=bit.que(f[j].m); 45 } 46 } 47 int main(){ 48 scanf("%d%d",&n,&k); 49 for(int i=1;i<=n;i++) 50 scanf("%d%d%d",&f[i].s,&f[i].c,&f[i].m); 51 sort(f+1,f+1+n,cmpAll); 52 cdq(1,n); 53 sort(f+1,f+1+n,cmpAll); 54 for(int i=1;i<=n;){ 55 int j=i,maxs=0; 56 while(f[i].s==f[j].s&&f[i].c==f[j].c&&f[i].m==f[j].m){ 57 maxs=max(maxs,f[j].sum); 58 j++; 59 } 60 ans[maxs]+=j-i; 61 i=j; 62 } 63 for(int i=0;i<=n-1;i++) 64 printf("%d\n",ans[i]); 65 return 0; 66 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用