[BZOJ 3295]动态逆序对

本文介绍了一种利用分块技术解决动态删除元素情况下逆序对计数的问题。通过将数组分为多个块,并为每个块维护有序列表,可以在删除元素后快速更新逆序对的数量。这种方法适用于需要频繁修改数据集并实时获取逆序对数量的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

每次删一个数,询问逆序对数量

分块大法好,暴力出奇迹


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define maxn 100010
#define Size 500
using namespace std;

void read(int &num){
	num = 0;char ch = getchar();
	for(; ch < '!'; ch = getchar());
	for(; ch > '!'; ch = getchar())
	    num = num * 10 + ch - 48;
}

int n, m;

int t[maxn], pos[maxn], here[maxn];

bool bo[maxn];

const int inf = 0x7fffffff;

struct block{
	int a[Size], sum, l, r, cnt;
	void build(int id){
		cnt = 0;
		for(int i = l; i <= r; i ++){
			a[++ cnt] = t[i];
			pos[i] = id;
			here[t[i]] = id;
		}
		sort(a + 1, a + 1 + cnt);
	}
	
	void rebuild(int p){
		for(int i = 1; i <= cnt; i ++)
			if(a[i] == p){
				a[i] = inf;
				break;
			}
        sort(a + 1, a + 1 + cnt);
        cnt --;bo[p] = true;
	}
	
	int small(int p){
        if(cnt == 0)return 0;
		int t = lower_bound(a + 1, a + 1 + cnt, p) - a;
		if(a[t] > p)t --;
		if(t > cnt)return cnt;
		return t;
	}
	
	int big(int p){
		if(cnt == 0)return 0;
		int t = lower_bound(a + 1, a + 1 + cnt, p) - a;
		if(a[t] > p)t --;
		if(t == 0)return cnt;
		if(t > cnt)return 0;
		return cnt - t;
	}
	
	int bruteforce(int p){
		int flag = true;
		int ret = 0;
		for(int i = l; i <= r; i ++){
			if(bo[t[i]])continue;
			if(t[i] == p){flag = false;continue;}
			if(flag && t[i] > p)ret ++;
			if(!flag && t[i] < p)ret ++;
		}
		return ret;
	}
}b[Size];

struct BIT{
	int t[maxn];
	int lowbit(int i){
		return i & -i;
	}
	void update(int pos, int val){
		for(int i = pos; i; i -= lowbit(i))
		    t[i] += val;
	}
	int ask(int pos){
		int ret = 0;
		for(int i = pos; i <= n; i += lowbit(i))
		    ret += t[i];
		return ret;
	}
}T;

long long getanti(){
	long long ans = 0;
	for(int i = 1; i <= n; i ++){
		ans += T.ask(t[i]);
		T.update(t[i], 1);
	}
	return ans;
}

int main(){
	read(n), read(m);
	for(int i = 1; i <= n; i ++)
		read(t[i]);
	int blo = sqrt(n);
	if(blo * blo < n)blo ++;
	for(int i = 1; i <= blo; i ++){
		int L = (i - 1) * blo + 1, R = i * blo;
		R = min(R, n);
		b[i].l = L, b[i].r = R;
		b[i].build(i);
		if(R == n){
			blo = i;
			break;
		}
	}
	long long ans = getanti();
	
	int x;
	for(int i = 1; i <= m; i ++){
		printf("%lld\n", ans);
		read(x);
		int t = here[x];
		ans -= b[t].bruteforce(x);
		for(int j = 1; j < t; j ++)
			ans -= b[j].big(x);
		for(int j = t + 1; j <= blo; j ++)
			ans -= b[j].small(x);
		b[t].rebuild(x);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值