题目链接: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. 【Salvation】——项目进展&已取得的成果

    写在前面:这个项目为原创团体项目,其中美术设计与部分关卡功能为其他成员完成,我负责的部分以角色动画和登录注册为主. 一.游戏美术设计 游戏背景,道具,动物,人物帧动画制作全部完成. 1.人物 2.游戏 ...

  2. Oracle内存管理(之五)

    [深入解析--eygle]学习笔记 1.4. 2其它内存组件 Large Pool-大池是SGA的一个可选组件,通经常使用于共享server模式(MTS). 并行计算或 RMAN的备份恢复等操作. J ...

  3. 微信小程序 - 关闭当前页面无法再通过左上角返回

    考试的时候不可能答完以后,得到成绩后再通过左上角返回再重新答吧? 可以通过:open-type='redirectTo'实现

  4. Android微信分享功能实例+demo

    Android微信分享功能实例 1 微信开放平台注册 2 获得appId,添加到程序中,并运行程序 3 使用应用签名apk生成签名,添加到微信开放平台应用签名,完成注册 4 测试分享功能. 有问题请留 ...

  5. Lua学习九----------Lua字符串

    © 版权声明:本文为博主原创文章,转载请注明出处 1.Lua字符串 - ''单引号间的一串字符 - ""双引号之间的一串字符 - [[]]之间的一串字符 2.Lua转义字符 3.字 ...

  6. LeetCode 之 Valid Palindrome(字符串)

    [问题描写叙述] Given a string, determine if it is a palindrome, considering only alphanumeric characters a ...

  7. 使用Docker开发NodeJs APP

    英文版原文地址 这是两篇连载文章的第一篇,讲解了如何使用 Docker 替代 Vagrant 开发基于 Express 框架的NodeJs App的部分细节.不过,这次要增加点难度:我们要使用 con ...

  8. js将字符串转变成数字

    方法主要有三种 转换函数.强制类型转换.利用js变量弱类型转换. 1. 转换函数: js提供了parseInt()和parseFloat()两个转换函数.前者把值转换成整数,后者把值转换成浮点数.只有 ...

  9. 四、Silverlight中使用MVVM(四)——演练

    本来打算用MVVM实现CRUD操作的,这方面例子网上资源还挺多的,毕竟CRUD算是基本功了,因为最近已经开始学习Cailburn框架了,感觉时间 挺紧的,这篇就实现其中的更新操作吧. 功能很明确,当我 ...

  10. 安装部署Solrcloud

    实验说明: 三台虚拟机做solrcloud集群                            安装solr前请确保jdk .tomcat.zookeeper已安装好,否则无法启动 三台虚拟机I ...