问题描述

LG1393


题解

本题可以使用\(\mathrm{CDQ}\)分治完成。


二维偏序

根据偏序的定义,逆序对是一个二维偏序,但这个二维偏序比较特殊:

  • \(i>j,a_i<a_j\)

  • \(i<j,a_i>a_j\)

以上两种情况都符合这个二维偏序。


三维偏序

但带修改二维偏序怎么做?

我们将删除操作视为插入操作。

则没有没删除的插入时间为\(1\),第\(i\)个被删除的,插入时间为\(m-i+2\)

将插入时间作为第一维,数列位置为第二维,数值为第三维。

做三维偏序即可。

注意由于逆序对的定义,三维偏序仍是两种情况。


\(\mathrm{CDQ}\)分治

简要介绍一下\(\mathrm{CDQ}\)分治。

\(\mathrm{CDQ}\)分治是一种分治算法(废话),是一个叫做陈丹琪的女选手在\(2009\)(记不清了)年提出的。当时提出时是用于优化一类\(\mathrm{DP}\)问题的。后来\(\mathrm{CDQ}\)分治被主要用于解决三维偏序问题。

\(\mathrm{CDQ}\)分治思想类似于归并排序。归并排序每次将区间\([l,r]\)划分为\([l, \lfloor\frac{l+r}{2} \rfloor]\)和\([\lfloor \frac{l+r}{2} \rfloor + 1,r]\)

考虑三维偏序问题模型,\(i\)对\(j\)有贡献需要满足\(a_i<a_j,b_i<b_j,c_i<c_j\)。

\(\mathrm{CDQ}\)分治先将\(a\)升序排序,再进行归并排序,使\(b\)有序。

考虑区间\([l,r]\),当完成左右区间的归并排序后,由于一开始先对\(a\)进行了排序,则\(\forall x \in[l, \lfloor\frac{l+r}{2} \rfloor],\forall y \in [\lfloor \frac{l+r}{2} \rfloor + 1,r]\),一定有\(a_x<a_y\),这时候分别维护左区间和右区间指针,同时用树状数组维护值即可。

具体请见【模板】三维偏序(陌上花开)题解区。


\(\mathrm{code}\)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,tmp;
struct node{
int a,b,c,ans;
}a[40007];
int anss[40007];
template<typename Tp>
void read(Tp &x){
x=0;char ch=1;int fh;
while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
if(ch=='-'){
ch=getchar();fh=-1;
}
else fh=1;
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
x*=fh;
} struct BIT{
int c[40007];
void change(int p,int k){
while(p<=40000){
c[p]+=k;p+=(p&(-p));
}
}
int query(int p){
int re=0;
while(p){
re+=c[p];p-=(p&(-p));
}
return re;
}
}T; bool comp(node a,node b){
if(a.a!=b.a) return a.a<b.a;
if(a.b!=b.b) return a.b<b.b;
return a.c<b.c;
} bool cmp(node a,node b){
if(a.b!=b.b) return a.b<b.b;
return a.c<b.c;
} bool fuck(node a,node b){
if(a.b!=b.b) return a.b>b.b;
return a.c>b.c;
} void cdq(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid);cdq(mid+1,r);
sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp);
int i,j=l,tot=0;
for(i=mid+1;i<=r;i++){
while(j<=mid&&a[j].b<=a[i].b){
T.change(a[j].c,1);++j;++tot;
}
a[i].ans+=tot-T.query(a[i].c);
}
for(i=l;i<j;i++) T.change(a[i].c,-1);
sort(a+l,a+mid+1,fuck);sort(a+mid+1,a+r+1,fuck);
for(i=mid+1,j=l;i<=r;i++){
while(j<=mid&&a[j].b>=a[i].b){
T.change(a[j].c,1);++j;
}
a[i].ans+=T.query(a[i].c);
}
for(i=l;i<j;i++) T.change(a[i].c,-1);
} bool fake(node a,node b){
return a.c<b.c;
} void lsh(){
sort(a+1,a+n+1,fake);
for(register int i=1;i<=n;i++) a[i].c=i;
} signed main(){
read(n);read(m);
for(register int i=1;i<=n;i++){
read(a[i].c);a[i].a=1,a[i].b=i;
}
for(register int i=1;i<=m;i++){
read(tmp);a[tmp].a=m-i+2;
}
lsh();
sort(a+1,a+n+1,comp);
cdq(1,n);
for(register int i=1;i<=n;i++) anss[a[i].a]+=a[i].ans;
for(int i=1;i<=n;i++)anss[i]+=anss[i-1];
for(int i=m+1;i>0;i--)printf("%lld%c",anss[i]," \n"[i==1]);
return 0;
}

LG1393 动态逆序对的更多相关文章

  1. 【LG1393】动态逆序对

    [LG1393]动态逆序对 题面 洛谷 题解 \(CDQ\)分治,按照时间来分治 应为一个删除不能对前面的操作贡献,所以考虑一个删除操作对它后面时间的操作的贡献 用上一个答案减去次贡献即可 代码 #i ...

  2. BZOJ 3295: [Cqoi2011]动态逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3865  Solved: 1298[Submit][Sta ...

  3. Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2886  Solved: 924[Submit][Stat ...

  4. 【Luogu1393】动态逆序对(CDQ分治)

    [Luogu1393]动态逆序对(CDQ分治) 题面 题目描述 对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i < j的有序对(i,j)的个数.你需要计算出一个序 ...

  5. 【BZOJ3295】动态逆序对(线段树,树状数组)

    [BZOJ3295]动态逆序对(线段树,树状数组) 题面 Description 对于序列A,它的逆序对数定义为满足iAj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的 ...

  6. bzoj3295[Cqoi2011]动态逆序对 树套树

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 5987  Solved: 2080[Submit][Sta ...

  7. cdq分治(hdu 5618 Jam's problem again[陌上花开]、CQOI 2011 动态逆序对、hdu 4742 Pinball Game、hdu 4456 Crowd、[HEOI2016/TJOI2016]序列、[NOI2007]货币兑换 )

    hdu 5618 Jam's problem again #include <bits/stdc++.h> #define MAXN 100010 using namespace std; ...

  8. P3157 [CQOI2011]动态逆序对(树状数组套线段树)

    P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...

  9. P3157 [CQOI2011]动态逆序对

    P3157 [CQOI2011]动态逆序对 https://www.luogu.org/problemnew/show/P3157 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai&g ...

随机推荐

  1. acwing 23. 矩阵中的路径

    习题地址 https://www.acwing.com/problem/content/description/21/ 题目描述请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路 ...

  2. 七夕节 (HDU - 1215) 【简单数论】【找因数】

    七夕节 (HDU - 1215) [简单数论][找因数] 标签: 入门讲座题解 数论 题目描述 七夕节那天,月老来到数字王国,他在城门上贴了一张告示,并且和数字王国的人们说:"你们想知道你们 ...

  3. Linux系统管理图文详解超详细精心整理

    前言:带你遨游于linux系统管理知识的海洋,沐浴春日里的阳光,循序渐进,看完之后收获满满. 本次讲解基于linux(centos6.5)虚拟机做的测试,centos7估计以后有时间再更新啊. lin ...

  4. vue的基础概念和语法01

    vue的特点和web开发中的常见高级功能 解耦视图和数据 可复用的组件 前端路由技术 状态管理 虚拟DOM 数据响应式 不是所有元素操作都Vue都会监听并实现数据响应式 //push方法:追加 thi ...

  5. Mac 应用程序不能打开解决方法

    Mac 应用程序不能打开解决方法 关键是 文件原本是可执行文件,由于权限丢失,才变成了类型不明的文件,导致软件无法打开. 参考: https://www.macbl.com/article/tips/ ...

  6. go语言使用go-sciter创建桌面应用(八) 窗口显示时,自动加载后端数据。

    有些时候我们需要在窗口创建并显示时,加载一些后端的配置,这就需要用到view提供的几个事件. https://sciter.com/docs/content/sciter/View.htm state ...

  7. ajax运行原理

    Ajax应用程序的加载过程与传统的Web应用程序类似.某个用户操作引发浏览器的一次HTTP请求.服务器接收请求并处理这个请求,生成合适的执行结果发送至客户端.客户端浏览器经过处理将数据(HTML+CS ...

  8. WPF 使用EventTrigger时设置SouceName技巧

    使用情节触发器时,如果有触发源/触发源控件时可以将情节触发器放置最顶级的面板控件的触发器中. 通过blend这个神器真的是可以学到不少东西. 代码: //情节动画放置于顶级控制面板 <Widno ...

  9. MySQL中的group_concat函数的使用

    本文通过实例介绍了MySQL中的group_concat函数的使用方法,比如select group_concat(name) . MySQL中group_concat函数 完整的语法如下: grou ...

  10. Caused by: org.springframework.data.mapping.PropertyReferenceException: No property id found for type Users!

    Spring Data JPA自定义Repository Caused by: org.springframework.data.mapping.PropertyReferenceException: ...