题目链接: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. 解决使用maven jetty启动后无法加载修改过后的静态资源

    jetty模式是不能修改js文件的,比如你现在调试前端js,发现在myeclipse/eclipse的源码里面无法修改文件,点都不让你点,所以,你只能采用一些办法,更改jetty的模式配置. Look ...

  2. ORACLE数据库导表

    今天在公司的server上面装一个系统,在数据库导表的时候一直导不进去,原先是10g的.dmp文件,导入11g.怀疑版本号不兼容,后来把.dmp表打开,把里面的版本号号改为11g,发现导入还是不行.i ...

  3. Shell脚本值:运算符

    算术运算符 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用. expr 是一款表达式计算工具,使用它能完成表达式的求值操作. 例如:实现两个 ...

  4. ViewPager+Fragment 滑动菜单效果 实现步骤

    1.xml中引用ViewPager     <android.support.v4.view.ViewPager             android:id="@+id/viewPa ...

  5. 重读金典------高质量C编程指南(林锐)-------第四章 表达式和基本语句

    4.1 运算符的优先级   规则:如果代码行中的运算符比较多,可用括号确定操作顺序.if((a|b)&&(a&c)) 4.2   复合表达式 规则:不要编写太复杂的复合表达式 ...

  6. Spring学习十三----------Spring AOP的基本概念

    © 版权声明:本文为博主原创文章,转载请注明出处 什么是AOP -面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 -主要的功能是:日志记录.性能统计.安全控制.事务处理. ...

  7. Lua学习一----------开发环境搭建

    © 版权声明:本文为博主原创文章,转载请注明出处 1.LuaDist下载地址:http://luadist.org/ 2.LuaRocks下载地址:https://github.com/luarock ...

  8. 使用构建工具gradle打包时,遇到的中文问题和解决方式

    1.使用gradle  clean  war 命令将项目打成war包.这一过程gradle没有提示报错. 2.将得到的myapp.war复制到tomcat下webapps(部署war包) 3.启动to ...

  9. Android Handler 异步消息处理机制的妙用 创建强大的图片载入类

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自[张鸿洋的博客] 近期创建了一个群.方便大家交流,群号: ...

  10. Rider

    听说你开发.NET还在用VS,小哥哥给你推荐全平台的Rider   本文地址:http://www.cnblogs.com/likeli/p/8461010.html 前言 .NET平台的开发一直都只 ...