题目链接:https://vjudge.net/problem/HYSBZ-3295

3295: [Cqoi2011]动态逆序对

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 6517  Solved: 2295
[Submit][Status][Discuss]

Description

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删
除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数

Input

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
以下n行每行包含一个1到n之间的正整数,即初始排列。
以下m行每行一个正整数,依次为每次删除的元素。
N<=100000 M<=50000

Output

 
输出包含m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4
1
5
3
4
2
5
1
4
2

Sample Output

5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

题解:

1.最核心的问题是:删除当前位置的数,会造成多少对逆序对的减少。

2.要统计删除当前数会造成多少对逆序对的减少,即需要统计:前面比它大的数的个数 + 后面比它小的数的个数 (前提是这些数没有被删除)。

3.由于题目还存在动态删除,则再为每个位置添加一个标志:Di,表明它是第几个被删除的。加上这个限制,就是一个三维偏序问题了。

4.以j为统计对象,sum[j]为删除位置j的数,所减少的逆序对。sum[j] = sum (i<j 且 Ai>Aj 且 Di>Dj)+ (j<i 且 Aj>Ai 且 Di>Dj)

5.得到sum数组之后,即知道删除当前位置的数,会造成多少对逆序对的减少。那么再算出初始的逆序对(不带删除,即二维偏序)即可。

写法一:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5+; struct node
{
int x, y, z;
};
node a[MAXN], b[MAXN], tmp[MAXN]; int n, m, c[MAXN];
int lowbit(int x) {return x&(-x);}
void add(int x, int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;}
int query(int x) {int ret=; for(int i=x;i>;i-=lowbit(i))ret+=c[i]; return ret;} int sum[MAXN], type;
void CDQ(int l, int r)
{
if(l==r) return; int mid = (l+r)>>;
CDQ(l, mid); CDQ(mid+, r);
int p1 = l, p2 = mid+;
for(int i = l; i<=r; i++)
{
if(p2>r||(p1<=mid&&a[p1].y>=a[p2].y)) b[i] = a[p1++];
else b[i] = a[p2++];
}
int cnt = ; //按删除顺序逆序排序了,所以先出现的更后删除
for(int i = l; i<=r; i++) //统计前面比它小的
{
a[i] = b[i];
if(a[i].x<=mid) add(a[i].z, ), cnt++;
else if(a[i].y!=INF) sum[a[i].y] += cnt-query(a[i].z);
}
for(int i = l; i<=r; i++)
if(a[i].x<=mid) add(a[i].z, -); for(int i = l; i<=r; i++) //统计后面比它大的
{
a[i] = b[i];
if(a[i].x>mid) add(a[i].z, );
else if(a[i].y!=INF) sum[a[i].y] += query(a[i].z-);
}
for(int i = l; i<=r; i++)
if(a[i].x>mid) add(a[i].z, -);
} int M[MAXN];
int main()
{
while(scanf("%d%d", &n,&m)!=EOF)
{
for(int i = ; i<=n; i++)
{
scanf("%d", &a[i].z);
M[a[i].z] = i;
a[i].x = i; a[i].y = INF;
}
for(int i = ; i<=m; i++)
{
int del;
scanf("%d", &del);
a[M[del]].y = i;
} LL ans = ;
memset(c, , sizeof(c));
for(int i = ; i<=n; i++)
{
ans += (i-)-query(a[i].z);
add(a[i].z, );
} memset(c, , sizeof(c));
memset(sum, , sizeof(sum));
CDQ(,n); printf("%lld\n", ans);
for(int i = ; i<m; i++)
{
ans -= sum[i];
printf("%lld\n", ans);
}
}
}

写法二:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int MOD = 1e9+;
const int MAXN = 1e5+; struct node
{
int x, y, z;
};
node a[MAXN], b[MAXN]; int n, m, c[MAXN];
int lowbit(int x) {return x&(-x);}
void add(int x, int val) {for(int i=x;i<=n;i+=lowbit(i)) c[i]+=val;}
int query(int x) {int ret=; for(int i=x;i>;i-=lowbit(i))ret+=c[i]; return ret;} int sum[MAXN], type;
void CDQ(int l, int r)
{
if(l==r) return; int mid = (l+r)>>;
CDQ(l, mid); CDQ(mid+, r);
int p1 = l, p2 = mid+;
for(int i = l; i<=r; i++)
{
if(p2>r||(p1<=mid&&a[p1].y>=a[p2].y)) b[i] = a[p1++];
else b[i] = a[p2++];
}
int cnt = ;
for(int i = l; i<=r; i++)
{
a[i] = b[i];
if(a[i].x<=mid) add(a[i].z, ), cnt++;
else if(a[i].y!=INF)
{
if(type) sum[a[i].y] += cnt-query(a[i].z);
else sum[a[i].y] += query(a[i].z-);
}
}
for(int i = l; i<=r; i++)
if(a[i].x<=mid) add(a[i].z, -);
} node tmp[MAXN];
int M[MAXN];
int main()
{
while(scanf("%d%d", &n,&m)!=EOF)
{
for(int i = ; i<=n; i++)
{
scanf("%d", &a[i].z);
M[a[i].z] = i;
a[i].y = INF;
}
for(int i = ; i<=m; i++)
{
int del;
scanf("%d", &del);
a[M[del]].y = i;
} LL ans = ;
memset(c, , sizeof(c));
for(int i = ; i<=n; i++)
{
ans += (i-)-query(a[i].z);
add(a[i].z, );
} memcpy(tmp, a, sizeof(tmp));
for(int i = ; i<=n; i++)
a[i].x = i;
memset(c, , sizeof(c));
type = ;
CDQ(,n); memcpy(a, tmp, sizeof(a));
reverse(a+,a++n);
for(int i = ; i<=n; i++)
a[i].x = i;
type = ;
CDQ(,n); printf("%lld\n", ans);
for(int i = ; i<m; i++)
{
ans -= sum[i];
printf("%lld\n", ans);
}
}
}

BZOJ3295 [Cqoi2011]动态逆序对 —— CDQ分治的更多相关文章

  1. [BZOJ3295][Cqoi2011]动态逆序对 CDQ分治&树套树

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MB Description 对于序列A,它的逆序对数定义为满足i<j,且 ...

  2. bzoj3295: [Cqoi2011]动态逆序对(cdq分治+树状数组)

    3295: [Cqoi2011]动态逆序对 题目:传送门 题解: 刚学完cdq分治,想起来之前有一道是树套树的题目可以用cdq分治来做...尝试一波 还是太弱了...想到了要做两次cdq...然后伏地 ...

  3. BZOJ3295:[CQOI2011]动态逆序对(CDQ分治)

    Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...

  4. 【BZOJ3295】[Cqoi2011]动态逆序对 cdq分治

    [BZOJ3295][Cqoi2011]动态逆序对 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依 ...

  5. bzoj3295 [Cqoi2011]动态逆序对 cdq+树状数组

    [bzoj3295][Cqoi2011]动态逆序对 2014年6月17日4,7954 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数. ...

  6. [CQOI2011]动态逆序对 CDQ分治

    洛谷上有2道相同的题目(基本是完全相同的,输入输出格式略有不同) ---题面--- ---题面--- CDQ分治 首先由于删除是很不好处理的,所以我们把删除改为插入,然后输出的时候倒着输出即可 首先这 ...

  7. 洛谷 P3157 [CQOI2011]动态逆序对 | CDQ分治

    题目:https://www.luogu.org/problemnew/show/3157 题解: 1.对于静态的逆序对可以用树状数组做 2.我们为了方便可以把删除当成增加,可以化动为静 3.找到三维 ...

  8. BZOJ 3295: [Cqoi2011]动态逆序对 [CDQ分治]

    RT 传送门 首先可以看成倒着插入,求逆序对数 每个数分配时间(注意每个数都要一个时间)$t$,$x$位置,$y$数值 $CDQ(l,r)$时归并排序$x$ 然后用$[l,mid]$的加入更新$[mi ...

  9. P3157 [CQOI2011]动态逆序对 CDQ分治

    一道CDQ分治模板题简单来说,这道题是三维数点对于离线的二维数点,我们再熟悉不过:利用坐标的单调递增性,先按更坐标排序,再按纵坐标排序更新和查询时都直接调用纵坐标.实际上,我们是通过排序将二维中的一维 ...

随机推荐

  1. 手机APP脚本录制(LoadRunner 12)

    最近因项目需要,研究了下手机APP脚本录制方法,有需要的童鞋可参考使用! 方法1: 在手机网络中设置网络代理,使用LR12选择Mobile Application – HTTP/HTML协议中代理录制 ...

  2. java8新特性学习笔记(二) 流的相关思想

    流是什么 流是Java API的新成员,他允许你以声明的方式处理数据集合,就现在来说,可以把他们看成遍历数据集合的高级迭代器.此外,流还可以透明地并行处理,你无须写任何多线程代码. 下面例子是新老AP ...

  3. 【小程序】微信小程序开发实践

    帐号相关流程 注册范围 企业 政府 媒体 其他组织 换句话讲就是不让个人开发者注册. :) 填写企业信息 不能使用和之前的公众号账户相同的邮箱,也就是说小程序是和微信公众号一个层级的. 填写公司机构信 ...

  4. websocket关于禁止一个账号多窗口链接的问题

    通过websocket的session.getSessionId()与oldSession.getSessionId()来equals判断是否是新窗口. 如果不同不让链接. 问题1.虽然新来的链接连不 ...

  5. Linux安装httpd2.4.10

    1. cd /mnt tar zxvf httpd-2.4.10.tar.gz ./configure --prefix=/mnt/apache2 --enable-dav --enable-modu ...

  6. Leet Code OJ 237. Delete Node in a Linked List [Difficulty: Easy]

    题目: Write a function to delete a node (except the tail) in a singly linked list, given only access t ...

  7. 多域名THINKPHP利用MEMCACHE方式共享SESSION数据(转)

    一.问题起源 稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名.密码在整个网站的各个模块中都是可以登录使 ...

  8. ios面试基础

    1.#import和#include的差别 @class? @class一般用于头文件里须要声明该类的某个实例变量的时候用到,在m文 件中还是须要使用#import 而#import比起#includ ...

  9. 在tomcat中用jndi配置数据源启动java web程序

    1.在web.xml中添加: <resource-ref>    <res-ref-name>jdbc/MTSDB</res-ref-name>    <re ...

  10. MySQL常见的数据类型(八)

    不多说,直接上干货! MySQL常见的数据类型 一.数据类型是什么? 数据类型是指列.存储过程参数.表达式和局部变量的数据特征,它决定了数据的存储格式,代表了不同的信息类型. 有一些数据是要存储为数字 ...