``Dynamic'' Inversion
64-bit integer IO format: %lld Java class name: Main
Problem D
"Dynamic" Inversion
You are given a permutation {1,2,3,...,n}. Remove m of them one by one, and output the number of inversion pairs before each removal. The number of inversion pairs of an array A is the number of ordered pairs (i,j) such that i < j and A[i] > A[j].
Input
The input contains several test cases. The first line of each case contains two integers n and m (1<=n<=200,000, 1<=m<=100,000). After that, n lines follow, representing the initial permutation. Then m lines follow, representing the removed integers, in the order of the removals. No integer will be removed twice. The input is terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each removal, output the number of inversion pairs before it.
Sample Input
5 4 1 5 3 4 2 5 1 4 2
Output for the Sample Input
5 2 2 1
Explanation
(1,5,3,4,2)->(1,3,4,2)->(3,4,2)->(3,2)->(3)
Rujia Liu's Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University
Special Thanks: Yi Chen, Dun Liang
Note: Please make sure to test your program with the gift I/O files before submitting!
#include <bits/stdc++.h>
int lowbit(int x) {return x & -x;}
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int M = 4e6 + 10;
int tot;
struct Splay {
int fa,key,siz;
int ch[2];
Splay() = default;
Splay(int fa,int key):fa(fa),key(key),siz(1){
ch[0] = ch[1] = 0;
}
}Node[M];
int newNode(int fa,int key)
{
int rt = ++tot;
Node[rt] = Splay(fa,key);
return rt;
}
int built(vector<int>&v,int fa,int l,int r)
{
int mid = (l + r) >> 1;
int rt = newNode(fa,v[mid-1]);
Splay & t = Node[rt];
if(mid > l) t.ch[0] = built(v,rt,l,mid-1);
if(mid < r) t.ch[1] = built(v,rt,mid+1,r);
t.siz += Node[t.ch[0]].siz + Node[t.ch[1]].siz;
return rt;
}
int ask(int rt,int x)///询问rt为根的子树里有多少不大于x的节点
{
if(!rt)return 0;
Splay & t = Node[rt];
if(t.key == x) {
return Node[t.ch[0]].siz+1;
}
bool flag = (t.siz - (Node[t.ch[0]].siz + Node[t.ch[1]].siz));///是否没被删除
if(t.key < x) return Node[t.ch[0]].siz + flag + ask(t.ch[1],x);
return ask(t.ch[0],x);
}
void remove(int rt,int x)
{
Splay & t = Node[rt];
--t.siz;
if(t.key==x)return;
remove(t.ch[t.key < x],x);
}
int n,m;
int root[N],pos[N];
vector<int>vec[N];
int c[N];
void add(int *T,int x,int d)
{
for(;x <= n; x += (x&-x)) {
T[x] += d;
}
}
int ask(int *T,int x)
{
int ans = 0;
for(;x > 0; x -= (x&-x)) {
ans += T[x];
}
return ans;
}
ll cnt;
int init()
{
if(scanf("%d%d",&n,&m)!=2) return 0;
memset(c,0,sizeof(int)*(n+1));
for(int i = 0; i <= n; ++i) vec[i].clear();
tot = cnt = 0;
Node[0].siz = 0;
for(int i = 1; i <= n; ++i) {
int x;
scanf("%d",&x);
cnt += (i-1)-ask(c,x);
add(c,x,1);
pos[x] = i;
for(int j = i; j <= n; j += (j&-j)) {
vec[j].push_back(x);
}
}
for(int i = 1; i <= n; ++i) {///可以通过打标记将删除变成静态的,直接按照完全二叉树来建树即可
sort(vec[i].begin(),vec[i].end());
root[i] = built(vec[i],0,1,vec[i].size());
}
return 1;
}
void change(int x,int val)
{
int t1 = 0,t2 = 0;
for(; x > 0; x -= (x&-x)) {
int t = ask(root[x],val); //查询root[x]里有多少个数小于等于val
t2 += t;
t1 += Node[root[x]].siz - t;//大于val的个数
}
t2 = ask(c,val) - t2;//后缀里小于val的个数
add(c,val,-1);//在val位置加-1
cnt -= (t1+t2);//删除之后对逆序对的影响
x = pos[val];
for( ;x <= n; x += (x&-x)) remove(root[x],val);//在受影响的平衡树中删除节点
}
int main()
{
while(init()) {
for(int i = 0; i < m; ++i) {
int x;scanf("%d",&x);
printf("%lld\n",cnt);
change(pos[x],x);
}
}
return 0;
}