【BZOJ3295】【块状链表+树状数组】动态逆序对
Description
Input
Output
Sample Input
1
5
3
4
2
5
1
4
2
Sample Output
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】【块状链表+树状数组】动态逆序对的更多相关文章
- POJ2299Ultra-QuickSort(归并排序 + 树状数组求逆序对)
树状数组求逆序对 转载http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html 转载: 树状数组,具体的说是 离散化+树 ...
- poj3067 Japan 树状数组求逆序对
题目链接:http://poj.org/problem?id=3067 题目就是让我们求连线后交点的个数 很容易想到将左端点从小到大排序,如果左端点相同则右端点从小到大排序 那么答案即为逆序对的个数 ...
- SGU180(树状数组,逆序对,离散)
Inversions time limit per test: 0.25 sec. memory limit per test: 4096 KB input: standard output: sta ...
- [NOIP2013提高&洛谷P1966]火柴排队 题解(树状数组求逆序对)
[NOIP2013提高&洛谷P1966]火柴排队 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相 ...
- [NOI导刊2010提高&洛谷P1774]最接近神的人 题解(树状数组求逆序对)
[NOI导刊2010提高&洛谷P1774]最接近神的人 Description 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某 ...
- 【bzoj2789】[Poi2012]Letters 树状数组求逆序对
题目描述 给出两个长度相同且由大写英文字母组成的字符串A.B,保证A和B中每种字母出现的次数相同. 现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B. 输入 第一行一个正整数n ...
- poj3067Japan——树状数组查找逆序对
题目:http://poj.org/problem?id=3067 利用树状数组查找逆序对. 代码如下: #include<iostream> #include<cstdio> ...
- “浪潮杯”第九届山东省ACM大学生程序设计竞赛(重现赛)E.sequence(树状数组求逆序对(划掉))
传送门 E.sequence •题意 定义序列 p 中的 "good",只要 i 之前存在 pj < pi,那么,pi就是 "good": 求删除一个数, ...
- 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)
2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...
- NOIP 2013 洛谷P1966 火柴排队 (树状数组求逆序对)
对于a[],b[]两个数组,我们应选取其中一个为基准,再运用树状数组求逆序对的方法就行了. 大佬博客:https://www.cnblogs.com/luckyblock/p/11482130.htm ...
随机推荐
- if form1.showmodal:=mrok then 什么意思
if form1.showmodal:=mrok then 这句话什么意思? 最佳答案 这个问题说来话长,且听我慢慢道来... 首先,你仔细看一看,所有的命令按钮(不论是Button还是BitBtn) ...
- hdu 4403 枚举
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #inclu ...
- 爬虫技术浅析 | z7y Blog
爬虫技术浅析 | z7y Blog 爬虫技术浅析
- 第十七章、程序管理与 SELinux 初探 工作管理 (job control)
工作管理 (job control) 这个工作管理 (job control) 是用在 bash 环境下的,也就是说:『当我们登陆系统取得 bash shell 之后,在单一终端机介面下同时进行多个工 ...
- hdu4431 Mahjong 枚举搜索。。
japanese麻将什么玩意..都没有豪华七对... 没什么难的 就是枚举搜索了 分三种类型的胡牌 f1是七对 f2是十三幺 f3是普通的胡牌 就先找一对 再找三个三个的 就是一直超时..在峰峰的指导 ...
- 1242Rescue (优先队列BFS)
Problem Description Angel was caught by the MOLIGPY! He was put in prison by Moligpy. The prison is ...
- windows系统下搭建linux
1.先装虚拟机VMware Workstation(步骤参照度娘) 2.在虚拟机上装CentOS6.5Linux系统(步骤参照度娘) 3.安装SecureCRT终端仿真程序,用来登录Linux服务 ...
- Maven学习系列二(1-5)
Maven学习系列二(1-5) 本文转自 QuantSeven 博客,讲解精炼易懂,适合入门,链接及截图如下 http://www.cnblogs.com/quanyongan/category/47 ...
- Linq to sql语法
LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子 ...
- servlet清晰理解
servlet介绍 Servlet看起来像是通常的Java程序.它是JSP的前身,在MVC架构中担任Controller的角色,即控制层.主要进行数据的处理操作和流程的控制,并将有关结果存储到Java ...