[BZOJ3295][Cqoi2011]动态逆序对

[BZOJ3295][Cqoi2011]动态逆序对

试题描述

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

输入

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

输出

输出包含m行,依次为删除每个元素之前,逆序对的个数。

输入示例

5 4
1
5
3
4
2
5
1
4
2

输出示例

5
2
2
1

数据规模及约定

N<=100000 M<=50000

题解

树状数组套主席树不解释。内存卡卡常。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
	return x * f;
}

#define maxn 100010
#define maxnode 10100000
#define LL long long

int ToT, sumv[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p, int v) {
	sumv[y = ++ToT] = sumv[x] + v;
	if(l == r) return ;
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
	if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
	else update(rc[y], rc[x], mid+1, r, p, v);
	return ;
}
int query(int o, int l, int r, int ql, int qr) {
	if(!o) return 0;
	if(ql <= l && r <= qr) return sumv[o];
	int mid = l + r >> 1, ans = 0;
	if(ql <= mid) ans += query(lc[o], l, mid, ql, qr);
	if(qr > mid) ans += query(rc[o], mid+1, r, ql, qr);
	return ans;
}

int n, A[maxn], pos[maxn], Rt[maxn], rt[maxn];
void modify(int x, int v) {
	for(; x <= n; x += x & -x) update(Rt[x], Rt[x], 1, n, v, -1);
	return ;
}
int ask(int x, int vl, int vr) {
	int ans = query(rt[x], 1, n, vl, vr);
	for(; x; x -= x & -x) ans += query(Rt[x], 1, n, vl, vr);
	return ans;
}

int main() {
//	freopen("data.in", "r", stdin);
//	freopen("data.out", "w", stdout);
	n = read(); int q = read();
	LL ans = 0;
	for(int i = 1; i <= n; i++) {
		A[i] = read(); pos[A[i]] = i;
		update(rt[i], rt[i-1], 1, n, A[i], 1);
		ans += query(rt[i-1], 1, n, A[i] + 1, n);
	}
	while(q--) {
		printf("%lld\n", ans);
		int p = pos[read()];
		modify(p, A[p]);
		ans -= ask(p - 1, A[p] + 1, n) + ask(n, 1, A[p] - 1) - ask(p, 1, A[p] - 1);
//		printf("ToT: %d\n", ToT);
	}
	
	return 0;
}

双倍经验:BZOJ2141,改改操作。。。

posted @ 2017-02-03 21:57  xjr01  阅读(189)  评论(0编辑  收藏  举报