前置:

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. [Cypress] Load Data from Test Fixtures in Cypress

    When creating integration tests with Cypress, we’ll often want to stub network requests that respond ...

  2. javascript学习笔记(一)-廖雪峰教程

    一. 基础 1.for in,for of和forEach 遍历的是对象的属性,因为数组也是对象,其内部的元素的索引就是其属性值.用该方式遍历数组就是获取了数组中的每一个元素的索引值(从0開始). 而 ...

  3. php学习之道:WSDL具体解释(一)

    WSDL文档使用web服务描写叙述语言来定义服务. 文档包含逻辑(抽象)部分和详细部分. 抽象部分用于定义独立于实现的数据类型和消息,详细部分定义一个endpoint怎样实现一个能够与外界进行交互的服 ...

  4. 公布IOS产品被拒后怎样再上传新公布包

    问题描写叙述: 前两天提交公司产品2.0.7版本号到苹果审核,昨天提示被拒绝. 被拒原因就不描写叙述了. 我们经过改动后.又一次打包上传,但是怎么也提交不了.由于在苹果后台上已经存在2.0.7版本号的 ...

  5. 开源 免费 java CMS - FreeCMS2.0 会员password设置

    项目地址:http://www.freeteam.cn/ password设置 从右側管理菜单点击password设置进入.   输入正确的当前password和新password后点击改动就可以.

  6. iOS应用主流UI架构实现

    一.介绍 如今iOS开发过程中,最常见的一种UI架构是:界面底部是四五个tab bar .中间是内容显示.顶部是包括标题及返回等操作button,当点击进入某个模块后可以点击进行返回.这样的架构的应用 ...

  7. oc20--继承2

    // // Phone.h #import <Foundation/Foundation.h> // 被继承的这个类我们称之为父类/ 超类 @interface Phone : NSObj ...

  8. 怎样在Android.mk上加宏定义【转】

    本文转载自:http://blog.csdn.net/ttxgz/article/details/7591282 很简单, LOCAL_CFLAGS += -DWHATEVERDEFINE 就可以了

  9. 第20章 Redis配置

    20.1 Redis基础配置文件 20.2 Redis备份(持久化) save 900 1 save 300 10 save 60 10000 # By default Redis will stop ...

  10. 1-1restful简介及资源介绍