Description

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

Input

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

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)。

HINT

N<=100000 M<=50000

【分析】

这种水题还弄了两节课...真是没法治了。

用很多种方法,最好理解的就是块状链表套树状数组,每个块状链表里面套一个二维的树状数组,再加上离散化。

将m序列中的每一个数字对应一个坐标(在n中坐标,n-数字大小)然后就可以做了。

我还开了3个一维树状数组,卡着时间过的。

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map> const int N = + ;
const int SIZE = ;//块状链表的根号50000
const int M = + ;
using namespace std;
typedef long long ll;
int lowbit(int x) {return x & -x;}
struct BLOCK_LIST{
int C[SIZE][SIZE];
int t[][SIZE];//关于a的离散化序列和b的离散化序列
void init(){
memset(C, , sizeof(C));
memset(t, , sizeof(t));
}
int sum(int x, int y){
int cnt = , f = y;
//int flag = x;
while (x > ){
while (y > ){
cnt += C[x][y];
y -= lowbit(y);
}
x -= lowbit(x);
y = f;
}
return cnt;
}
void add(int x, int y){
int f = y;
while (x < SIZE){
while (y < SIZE){
C[x][y]++;
y += lowbit(y);
}
x += lowbit(x);
y = f;
}
return;
}
//二分搜索,查找x在k内相当的值
int search(int k, int x){
int l = , r = , Ans;
while (l <= r){
int mid = (l + r) >> ;
if (t[k][mid] <= x) Ans = mid, l = mid + ;
else r = mid - ;
}
return Ans;
}
}list[SIZE];
struct DATA{
int t[];//影响m的树状数组的两个值,注意都要进行离散化
int x;//值
}rem[M];
struct LSH{
int num, order;
bool operator < (LSH b)const{
return num < b.num;//专门用来离散化
}
}A[M];
int data[N], c[][N], n, m;
int num[N];//num[N]代表i有i存在的逆序对的个数
ll tot;//记录逆序对的个数 ll sum(int k, int x){
ll cnt = ;
while (x > ){
cnt += c[k][x];
x -= lowbit(x);
}
return cnt;//记得要用ll
}
void add(int k, int x){
while (x <= n){
c[k][x]++;
x += lowbit(x);
}
return;
}
void init(){
tot = ;
memset(num, , sizeof(num));
memset(c, , sizeof(c));
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++){
int x;
scanf("%d", &x);
data[x] = i;
int tmp = sum(, x);
num[x] += (i - - tmp);//先求出在i之前的比i大的数
num[x] += (x - tmp - );//后面比i小的数
tot += (i - - tmp);
add(, x);
}
//printf("%d\n", tot);
//for (int i = 1; i <= n; i++) printf("%d\n", num[i]);
}
//离散化
void prepare(){
//a,b中两个值分别为位置和大小
for (int i = ; i <= m; i++){
int tmp;
scanf("%d", &tmp);
rem[i].t[] = data[tmp];
rem[i].t[] = n - tmp + ;
rem[i].x = tmp;
}
//for (int i = 1; i <= m; i++) printf("%d %d %d\n", rem[i].t[0], rem[i].t[1], rem[i].x);
}
void get(int k, int l, int r, int x){
int cnt = r - l + , pos = ;
for (int i = l; i <= r; i++){
A[pos].order = i;
A[pos].num = rem[i].t[k];
pos++;
}
sort(A + , A + cnt + );
for (int i = ;i <= cnt; i++) list[x].t[k][i] = A[i].num;
for (int i = ;i <= cnt; i++) rem[A[i].order].t[k] = i;
}
void work(){
for (int i = ; i < SIZE; i++) list[i].init();
int cnt = ;//cnt是用来记录块的数量
for (int pos = ; pos <= m; pos++){ int l = pos;
l = min(m , + pos - );
//从[l,m]这一段放在list[cnt]里面
get(, pos, l, cnt);
get(, pos, l, cnt);
for (int i = pos; i <= l; i++){
printf("%lld\n", tot);
int tmp = list[cnt].sum(rem[i].t[], rem[i].t[]);
for (int j = ; j < cnt; j++) tmp += list[j].sum(list[j].search(, list[cnt].t[][rem[i].t[]]), list[j].search(, list[cnt].t[][rem[i].t[]])); tot -= (num[rem[i].x] - (tmp + (sum(, rem[i].x) - (sum(, list[cnt].t[][rem[i].t[]]) - tmp))));
list[cnt].add(rem[i].t[], rem[i].t[]);
add(, list[cnt].t[][rem[i].t[]]);
add(, rem[i].x);
}
cnt++;
pos = l;
}
} int main(){
#ifdef LOCAL
freopen("data.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
init();
prepare();
if (m == ) return ;
else work();
return ;
}

【BZOJ3295】【块状链表+树状数组】动态逆序对的更多相关文章

  1. POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)

    树状数组求逆序对   转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...

  2. poj3067 Japan 树状数组求逆序对

    题目链接:http://poj.org/problem?id=3067 题目就是让我们求连线后交点的个数 很容易想到将左端点从小到大排序,如果左端点相同则右端点从小到大排序 那么答案即为逆序对的个数 ...

  3. SGU180(树状数组,逆序对,离散)

    Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: sta ...

  4. [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)

    [NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...

  5. [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)

    [NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...

  6. 【bzoj2789】[Poi2012]Letters 树状数组求逆序对

    题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n ...

  7. poj3067Japan——树状数组查找逆序对

    题目:http://poj.org/problem?id=3067 利用树状数组查找逆序对. 代码如下: #include<iostream> #include<cstdio> ...

  8. “浪潮杯”第九届山东省ACM大学生程序设计竞赛(重现赛)E.sequence(树状数组求逆序对(划掉))

    传送门 E.sequence •题意 定义序列 p 中的 "good",只要 i 之前存在 pj < pi,那么,pi就是 "good": 求删除一个数, ...

  9. 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)

    2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...

  10. NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)

    对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...

随机推荐

  1. if form1.showmodal:=mrok then 什么意思

    if form1.showmodal:=mrok then 这句话什么意思? 最佳答案 这个问题说来话长,且听我慢慢道来... 首先,你仔细看一看,所有的命令按钮(不论是Button还是BitBtn) ...

  2. hdu 4403 枚举

    #include<cstdio> #include<cstring> #include<iostream> #include<cmath> #inclu ...

  3. 爬虫技术浅析 | z7y Blog

    爬虫技术浅析 | z7y Blog 爬虫技术浅析

  4. 第十七章、程序管理与 SELinux 初探 工作管理 (job control)

    工作管理 (job control) 这个工作管理 (job control) 是用在 bash 环境下的,也就是说:『当我们登陆系统取得 bash shell 之后,在单一终端机介面下同时进行多个工 ...

  5. hdu4431 Mahjong 枚举搜索。。

    japanese麻将什么玩意..都没有豪华七对... 没什么难的 就是枚举搜索了 分三种类型的胡牌 f1是七对 f2是十三幺 f3是普通的胡牌 就先找一对 再找三个三个的 就是一直超时..在峰峰的指导 ...

  6. 1242Rescue (优先队列BFS)

    Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is ...

  7. windows系统下搭建linux

    1.先装虚拟机VMware Workstation(步骤参照度娘) 2.在虚拟机上装CentOS6.5Linux系统(步骤参照度娘)   3.安装SecureCRT终端仿真程序,用来登录Linux服务 ...

  8. Maven学习系列二(1-5)

    Maven学习系列二(1-5) 本文转自 QuantSeven 博客,讲解精炼易懂,适合入门,链接及截图如下 http://www.cnblogs.com/quanyongan/category/47 ...

  9. Linq to sql语法

    LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...

  10. servlet清晰理解

    servlet介绍 Servlet看起来像是通常的Java程序.它是JSP的前身,在MVC架构中担任Controller的角色,即控制层.主要进行数据的处理操作和流程的控制,并将有关结果存储到Java ...