问题描述

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. <Graph> Topological + Undirected Graph 310 Union Find 261 + 323 + (hard)305

    310. Minimum Height Trees queue:  degree为1的顶点 degree[ i ] : 和 i 顶点关联的边数. 先添加整个图,然后BFS删除每一层degree为1的节 ...

  2. 用CSS绘制实体三角形

    用CSS绘制实体三角形 使用CSS盒模型中的border(边框)即可实现如下所示的三角形: .box { width: 0; height: 0; border-width: 100px; borde ...

  3. 模拟ssh远程执行命令

    目录 一.服务端 二.客户端 一.服务端 from socket import * import subprocess server = socket(AF_INET, SOCK_STREAM) se ...

  4. springboot实践1

    环境安装 安装jdk 推荐安装jkd1.8+,我使用的是mac,假设已经安装好homebrew,则jdk的安装指令是: brew install java 在 ~/zshrc ,添加两行 export ...

  5. jvm 性能调优工具之 jstat

    概述 Jstat是JDK自带的一个轻量级小工具.全称“Java Virtual Machine statistics monitoring tool”,它位于java的bin目录下,主要利用JVM内建 ...

  6. 二级目录下的运行main.py,找不到上级目录的解决方法

    import os, sys sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

  7. Vue-router中的history模式和hash模式

    还记得在我们从零开始搭建一个Vue-cli3.0项目时,预设置中出现过这样一条询问: 即是否选择历史模式,当时我们很坚决地选了否,那么哈希模式和历史模式究竟有什么区别,今天我们来一探究竟. 哈希模式( ...

  8. 远程连接docker

    vim /usr/lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix: ...

  9. JS基础语法---循环语句之:for 循环 + 9个练习

    for循环 语法: for(表达式1;表达式2;表达式3){ 循环体; } 执行过程: 先执行一次表达式1,然后判断表达式2;如果不成立则直接跳出循环 如果表达式2成立,执行循环体的代码,结束后,跳到 ...

  10. vue学习笔记(三): 启动说明

    1.启动页面:index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...