【bzoj3295】动态逆序对 分块+树状数组

题目描述

给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数。

代码

#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;

typedef long long lint;

const int N=100010;
const int BLOCK_SIZE=1000;
const int BLOCK_NUM=101;

int n,m;

int a[N];
int loc[N];

lint t[N];
lint res;

int num;
lint tr[BLOCK_NUM][N];

inline int read(void)
{
    int x=0; char c=getchar();
    for (;!isdigit(c);c=getchar());
    for (;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x;
}

inline int lowbit(int i)
{
    return i&-i;
}

inline void ins(lint *ta,int i,int add)
{
    for (;i<=n;i+=lowbit(i)) ta[i]+=add;
}

inline lint query(lint *ta,int i)
{
    lint sum=0;
    for (;i;i-=lowbit(i)) sum+=ta[i];
    return sum;
}

inline void update(int x)
{
    int loca=loc[x],bel=(loca-1)/BLOCK_SIZE+1;

    for (int i=BLOCK_SIZE*(bel-1)+1;i<loca;i++)
        if (a[i]>0&&a[i]>x) res--;
    for (int i=loca+1;i<=min(BLOCK_SIZE*bel,n);i++)
        if (a[i]>0&&a[i]<x) res--;

    lint tmp;
    for (int i=1;i<bel;i++)
    {
        tmp=query(tr[i],n)-query(tr[i],x-1);
        res-=tmp;
    }
    for (int i=bel+1;i<=num;i++)
    {
        tmp=query(tr[i],x-1);
        res-=tmp;
    }

    a[loca]=0;
    ins(tr[bel],x,-1);
}

int main(void)
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);

    n=read(),m=read();

    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1;i<=n;i++) loc[a[i]]=i;

    lint tmp;
    for (int i=n;i>=1;i--)
    {
        tmp=query(t,a[i]);
        res=res+tmp;
        ins(t,a[i],1);
    }

    int belo;
    num=(n-1)/BLOCK_SIZE+1;
    for (int i=1;i<=n;i++)
    {
        belo=(i-1)/BLOCK_SIZE+1;
        ins(tr[belo],a[i],1);
    }

    for (int i=1;i<=m;i++)
    {
        printf("%lld\n",res);
        update(read());
    }

    return 0;
}
时间: 2024-08-07 20:49:09

【bzoj3295】动态逆序对 分块+树状数组的相关文章

求逆序对 (树状数组版)

基本思想和线段树求解逆序数是一样的,前一篇<求逆序对 线段树版>也介绍过,先对输入数组离散,数组里的元素都不相同可以直接hash,存在相同的数话可以采用二分. 离散化后对于每个f[i],找到f[i]+1~ n中的个数,也就是到i这个位置,一共有多少比f[i]大的数,统计之后在将f[i]的位置上的数量加1. 这样一来统计的就是类似a[i]~n的和,可以想象成 把树状数组反过来统计,即统计的时候加lowbit,更新的时候减lowbit. 还是 以POJ 2299为例. #include <i

逆序对 (树状数组 | | 归并排序

数组前面的一个元素 大于等于 后面的一个元素就是一个逆序对: 树状数组可以快速求前缀和,利用这一特性,可以求逆序对个数,见下: 用数组c[ i ]记录数组a[ n ]中i这一元素出现的次数 ,当a[ n ]中元素较大时可以离散化处理. 将a[ n ]从a[n -1]到a[0] 依次存到树状数组中,每存一个,对存的元素i求一次c[i]的前缀和, 这就是当前已扫描过的比i小的元素的个数,由于a[n]是倒着扫描的,所以此时比i小的元素都对应一个逆序对,统计之. #include <cstdio> #

用树状数组处理逆序对[数据结构][树状数组]

逆序对 ——!x^n+y^n=z^n 可以到这里[luogu]: https://www.luogu.org/problem/show?pid=1908 题意:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. 假如为这些数为: 8 2 3 1 7 如果我们把数一个个加进来,用一个数组a[i]统计i出现了几次. a的初始状态: 8加进来后: 由于不存在比8大的数,说明没有产生逆序对 2加进来后: 统计比2大

hdu 4911 求逆序对数+树状数组

http://acm.hdu.edu.cn/showproblem.php?pid=4911 给定一个序列,有k次机会交换相邻两个位置的数,问说最后序列的逆序对数最少为多少. 实际上每交换一次能且只能减少一个逆序对,所以问题转换成如何求逆序对数. 归并排序或者树状数组都可搞 树状数组: 先按大小排序后分别标号,然后就变成了求1~n的序列的逆序数,每个分别查询出比他小的用i减,在把他的值插入即可 #include <cstdio> #include <cstdlib> #includ

Day2:T4求逆序对(树状数组+归并排序)

T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*(); B[J]>=B[I] 也就是求逆序对: 求逆序对的方法主要有两种: 归并排序: 树状数组: 这里两种方法都学习一下: 1.之前对于树状数组的印象就只有单点修改和区间求和 一直觉得lowbit是一个神奇的东西(至今没有搞懂原理) 上网搜了一下用树状数组求逆序对的方法,发现有一个大神写的很棒....看

P1908 逆序对-(树状数组)

https://www.luogu.org/problem/P1908 比较喜欢线段树,懒得用树状数组(只会套模板,位运算的精髓没有领悟到),一直没有记录树状数组代码,又得捡回来,趁这道题记录一下模板,为三维偏序cdq套树状数组铺垫一下. 解题思路:先对原数组a从大到小排序,依次添加进树状数组c里,每次求前缀和的结果就是 当前数的逆序对的个数. 例如数据:55,44,22,66,33,11 初始化树状数组c,清0: 添加66到4号位,则添加数组为 0,0,0,1,0,0: 66前没有比它大的数,

Codeforces Round #301 (Div. 2) E. Infinite Inversions —— 逆序对 离散化 + 树状数组

题目链接:http://codeforces.com/contest/540/problem/E E. Infinite Inversions time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output There is an infinite sequence consisting of all positive integers in

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间 [l,r]中妹子们美丽度的逆序对数吗?" 蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线." 请你帮助一下Autumn吧.