对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下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
二话不说上树套树。用树状数组套平衡树。顺着蓝书上的思路走,我们不妨可以用Splay代替普通平衡树来获得更方便的查询操作。事实证明用Splay的速度也是很可观的。值得注意的是,删除操作并不用将节点直接真正的删除,而可以做一个“假删除”——把节点留下,权值为0,可以减少代码量。
这里提供一个常数巨大的代码……
#include<cstdio> #define lowbit(x) ((x) & (-x)) using namespace std; const int maxn = 1e5 + 5; int n, m; long long ans; int org[maxn]; inline void read(int & x) { x = 0;char c = getchar(); while(c > '9' || c < '0') c = getchar(); while(c <= '9' && c >= '0') x = x * 10 + c - '0', c = getchar(); } namespace Splay { struct node { int ch[2], num, sum, cnt, fa; }tree[maxn * 30]; int cnt; void push_up(int rt) { if(rt == 0) return; int tl = tree[rt].ch[0]; int tr = tree[rt].ch[1]; tree[rt].sum = tree[rt].cnt + tree[tl].sum + tree[tr].sum; } void rotate(int rt) { int p = tree[rt].fa; int a = tree[p].fa; int l = tree[p].ch[1] == rt; int r = l ^ 1; if(a) tree[a].ch[tree[a].ch[1] == p] = rt; tree[rt].fa = a, tree[p].fa = rt, tree[tree[rt].ch[r]].fa = tree[rt].ch[r] ? p : 0; tree[p].ch[l] = tree[rt].ch[r], tree[rt].ch[r] = p; push_up(p), push_up(rt); } void splay(int x, int y, int & root) { int des = tree[y].fa; while(tree[x].fa != des) { int p = tree[x].fa; int a = tree[p].fa; if(a) if((tree[p].ch[1] == x) ^ (tree[a].ch[1] == p)) rotate(x); else rotate(p); rotate(x); } if(y == root) root = x; push_up(x); // 如果没有伸展 } void insert(int & root, int & now, int x, int last) { if(now == 0) { now = ++cnt, tree[now] = (node) {0, 0, x, 1, 1, last}; splay(now, root, root);return ;} if(tree[now].num == x) {++tree[now].cnt, ++tree[now].sum, splay(now, root, root); return;} insert(root, tree[now].ch[tree[now].num < x], x, now); push_up(now); } int find(int x, int root) { int rt = root, last = 0, lm = 0; while(tree[rt].num != x && rt != 0) { if(tree[rt].num <= x && tree[rt].num > lm) lm = tree[rt].num, last = rt; rt = tree[rt].ch[x > tree[rt].num]; } return rt == 0 ? last : rt; } void del(int x, int & root) { int rt = find(x, root); --tree[rt].sum, --tree[rt].cnt; splay(rt, root, root); } int query(int x, int & root, bool type) { // 0小 1大 int rt = find(x, root); if(rt == 0) return type ? tree[root].sum : 0; splay(rt, root, root); int ret = tree[tree[root].ch[type]].sum; if(x != tree[rt].num && type == 0) ret += tree[rt].cnt; return ret; } } namespace BIT{ int root[maxn << 4], N; void init(int n){N = n;} int add(int pos, int num) { while(pos <= N) Splay::insert(root[pos], root[pos], num, 0), pos += lowbit(pos); } void del(int pos, int num) { while(pos <= N) Splay::del(num, root[pos]), pos += lowbit(pos); } int query(int pos, int num, bool type) { int ret = 0; while(pos) { ret += Splay::query(num, root[pos], type); pos -= lowbit(pos); } return ret; } } namespace WBIT{ int tree[maxn << 4], N; void init(int n) {N = n;} void add(int pos) {while(pos <= N) ++tree[pos], pos += lowbit(pos);} int query(int pos) {int ret = 0;while(pos) ret += tree[pos], pos -= lowbit(pos);return ret;} } int main() { read(n), read(m); int a; BIT::init(n); WBIT::init(n); for(register int i = 1; i <= n; ++i) { read(a), org[a] = i; BIT::add(i, a); ans += i - WBIT::query(a) - 1, WBIT::add(a); } for(register int i = 1; i <= m; ++i) { read(a); long long sol1 = BIT::query(org[a], a, 1); long long sol2 = BIT::query(n, a, 0) - BIT::query(org[a], a, 0); printf("%lld\n", ans); ans -= (sol1 + sol2); BIT::del(org[a], a); } return 0; }
没有帐号? 立即注册