前置:

nlogn逆序对:

前一个小时我还真的不会这个Orz

这里运用归并排序的思想。

对于一个序列,我们把它先分开,再合并成一个有序序列。

引自https://blog.csdn.net/qq_30189255/article/details/50937307

假设f(i,j)为i到j号元素中的逆序对个数,取一个分割点k,假设s(i,j,k)表示以k为分割点,第一个元素在i到k中,第二个元素在k+1到j中形成的逆序对数。那么我们就得到一个递归式:f(i,j)=f(i,k)+f(k+1,j)+s(i,j,k)。很自然的与归并排序联系到了一起,对于更小规模的f可以递归求解,如果对于a数组的i到k以及k+1到j两个部分元素均为有序的情况,那么对于当a[j]<a[i]的情况,必然有a[j]<a[i..k],即a[j]和i到k号元素都形成逆序对,此时只要将s(i,j,k)加上k-i+1就可以了(i到k之间的元素个数),这个过程很像归并排序的Merge的过程——比较当前i和j的状态并放入较小的。于是我们就得到了算法,和归并排序一起操作:外围设置一个计数器count,每次归并过程分为分割与合并两个部分,分割照常处理,在合并部分中的if (a[i]>a[j]) b[++l]=a[++j];中加入一个计数过程,即cnt+=k-i+1。这样当排序完成后,统计也就完成了。

代码如下

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,a[50005],b[50005];
int merge(int l,int r) {
int ans=0;
if(l>=r) return 0;
int mid=l+r>>1;
ans+=merge(l,mid),ans+=merge(mid+1,r);
int i=l,j=mid+1,k=0,cnt=0;
while(i<=mid&&j<=r) {
if(a[i]<=a[j]) b[k++]=a[i++];
else cnt+=mid-i+1,b[k++]=a[j++];
}
while(j<=r) b[k++]=a[j++];
while(i<=mid) b[k++]=a[i++];
for(k=0;k<r-l+1;k++) {
a[l+k]=b[k];
}
return cnt+ans;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
cout<<merge(1,n);
}

这种问题又叫二维偏序,因为有两个维度:位置,数值

那么三维偏序呢?

IOI2019金牌选手GhostCai发明的czq分治

dalao陈丹琦发明的算法叫cdq分治

例题:陌上花开https://www.luogu.org/problemnew/show/P3810

cdq+树状数组 引自 https://blog.csdn.net/reverie_mjp/article/details/52462651

【对于本题来说,每个操作包含三维,首先按第一维关键字排序,并去重,数组中记录相同的花有多少朵。然后CDQ分治处理,处理时,将[l,mid]区间和[mid+1,r]区间分别按第二维关键字排序,并用树状数组以第三维为下标,维护每一朵花的出现次数。每一次处理[l,mid]对[mid+1,r]的影响时,只需考虑第二维的影响即可(因为[l,mid]区间的x一定小于[mid+1,r]区间的x,而第三维用树状数组维护也不需要考虑),当第二维符合要求时,将它的影响加入树状数组中。每查找完[mid+1,r]区间的一个操作,就更新答案】

#include <cstdio>
#include <algorithm>
using namespace std;
int t[500005];
int n,m;
const int N=500005;
struct Node {
int x,y,z,cnt,ans;
bool operator == (const Node &rhs)const {
return x==rhs.x&&y==rhs.y&&z==rhs.z;
}
} a[N],stk[N];
bool cmp(Node x,Node y) {
return x.x==y.x?(x.y==y.y?x.z<y.z:x.y<y.y):x.x<y.x;
}
void add(int x,int y) {
for(int i=x; i<=m; i+=i&-i)
t[i]+=y;
}
int ask(int x) {
int res=0;
for(int i=x; i; i-=i&-i)
res+=t[i];
return res;
}
void merge(int l,int r) {
if (l==r)
return;
int mid=l+r>>1;
merge(l,mid);
merge(mid+1,r);
int i=l,j=mid+1,k=0;
while(i<=mid&&j<=r) {
while(i<=mid&&a[i].y<=a[j].y) add(a[i].z,a[i].cnt),stk[++k]=a[i++];
while(j<=r&&a[j].y<a[i].y) a[j].ans+=ask(a[j].z),stk[++k]=a[j++];
}
while(i<=mid) add(a[i].z,a[i].cnt),stk[++k]=a[i++];
while(j<=r) a[j].ans+=ask(a[j].z),stk[++k]=a[j++];
for(int i=l; i<=mid; i++) add(a[i].z,-a[i].cnt);
for(int i=l; i<=r; i++) a[i]=stk[i-l+1]; }
int d[N];
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),a[i].cnt=1;
}
sort(a+1,a+1+n,cmp);
int cnt=0;
for(int i=1; i<=n; i++) {
if(a[i]==a[i-1]&&i!=1) a[cnt].cnt++;
else cnt++,a[cnt]=a[i];
}
swap(n,cnt);
merge(1,n);
for(int i=1; i<=n; i++) d[a[i].ans+a[i].cnt]+=a[i].cnt;
for(int i=1; i<=cnt; i++) printf("%d\n",d[i]);
}

nlogn求逆序对&&陌上花开的更多相关文章

  1. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  2. 归并排序+归并排序求逆序对(例题P1908)

    归并排序(merge sort) 顾名思义,这是一种排序算法,时间复杂度为O(nlogn),时间复杂度上和快排一样 归并排序是分治思想的应用,我们先将n个数不断地二分,最后得到n个长度为1的区间,显然 ...

  3. HDU 3743 Frosh Week(归并排序求逆序对)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3743 题目意思就是给你一个长为n的序列,让你求逆序对.我用的是归并排序来求的.归并排序有一个合并的过程 ...

  4. AC日记——codevs 1688 求逆序对

    1688 求逆序对  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 给定一个序列a1,a2,…, ...

  5. codevs1688 求逆序对

    题目描述 Description 给定一个序列a1,a2,…,an,如果存在i<j并且ai>aj,那么我们称之为逆序对,求逆序对的数目 数据范围:N<=105.Ai<=105. ...

  6. HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 解题报告: 给出一个长度为n的序列,然后给出一个k,要你求最多做k次相邻的数字交换后,逆序数最少 ...

  7. SGU 180 Inversions(离散化 + 线段树求逆序对)

    题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=180 解题报告:一个裸的求逆序对的题,离散化+线段树,也可以用离散化+树状数组.因为 ...

  8. 树状数组求逆序对:POJ 2299、3067

    前几天开始看树状数组了,然后开始找题来刷. 首先是 POJ 2299 Ultra-QuickSort: http://poj.org/problem?id=2299 这题是指给你一个无序序列,只能交换 ...

  9. wikioi 1688 求逆序对

    /*=========================================================== wikioi 1688 求逆序对 时间限制: 1 s 空间限制: 12800 ...

随机推荐

  1. visual studio 开发工具SVN集成工具,测试可用,成功集成

    使用说明:https://www.xiazaiba.com/html/24864.html 下载地址:点击下载集成插件

  2. phpfpm的配置

    1.php中fastcgi和php-fpm是什么东西 最近在研究和学习PHP的性能方面的知识,看到了factcgi以及php-fpm,发现我对他们是少之又少的理解,可以说几乎是一无所知,想想还是蛮可怕 ...

  3. 2016.04.25,英语,《Vocabulary Builder》Unit 18

    capit, from the Latin word for 'head', caput ['keɪpət] n.头,首 , turns up in some pretty important pla ...

  4. 轻快的vim(一):移动

    断断续续的使用VIM也一年了,会的始终都是那么几个命令,效率极低 前几个星期把Windows换成了Linux Mint,基本上也稳定了下来 就今晚,我已经下定决心开始新的VIM之旅,顺便写一系列的笔记 ...

  5. 在Spring Boot中使用Spring-data-jpa实现分页查询

    转自:https://www.cnblogs.com/sandea/p/8275890.html 在我们平时的工作中,查询列表在我们的系统中基本随处可见,那么我们如何使用jpa进行多条件查询以及查询列 ...

  6. thymeleaf 引入js css 无效

    转自:https://blog.csdn.net/qq_33833327/article/details/81388502

  7. WPF中ListBox ListView数据翻页浏览笔记(强调:是数据翻页,非翻页动画)

    ListBox和ListView在应用中,常常有需求关于每页显示固定数量的数据,然后通过Timer自动或者手动翻页操作,本文介绍到的就是该动作的实现. 一.重点 对于ListBox和ListView来 ...

  8. 使用 `ConfigMap` 挂载配置文件

    使用 ConfigMap 挂载配置文件 Intro 有一些敏感信息比如数据库连接字符串之类的出于安全考虑,这些敏感信息保存在了 Azure KeyVault 中,最近应用上了 k8s 部署,所以想把 ...

  9. Python基础:lambda 匿名函数

    格式 lambda argument1, argument2,... argumentN : expression square = lambda x: x**2 print(square(2)) 与 ...

  10. Sybase 动态改变存储过程里查询的数据库

    declare @sql varchar(500) select @sql='select * from '+@dbName+'..tableName' --此句用于执行拼接好的SQL语句 exec( ...