您的位置:首页 > 理论基础 > 数据结构算法

UVA11990 ``Dynamic'' Inversion (树状数组套平衡树)

2015-08-24 15:19 405 查看


``Dynamic'' Inversion

Time Limit: 3000ms
Memory Limit: 131072KB

This problem will be judged on UVA. Original ID: 11990

64-bit integer IO format: %lld      Java class name: Main

Prev Submit Status Statistics Discuss Next

Font Size: 
+
 
-

[PDF Link]


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!

Prev Submit Status Statistics Discuss Next

给你一个1到n的排列,进行m次删除操作,输出每次删除之前的逆序对数,静态逆序对可以用归并排序或者树状数组来求,动态的可以用树状数组套平衡树来求,具体来说,就是树状数组的每个节点是一颗平衡树,第x个节点保存x,x-1,x-2...,x-lowbit(x)+1的所有值(建成平衡树),假设要删除的数是x[i]在原排列中的位置是pos[i],我们只需要知道1到pos[i-1]中有多少个数比x[i]大和pos[i+1]到结尾有多少个数比x[i]小,就能知道逆序对减少了多少(已经删除的点直接忽略掉).那么我们可以通过在pos[i],pos[i]-lowbit(pos[i]),pos[i]-lowbit(pos[i])
- lowbit(pos[i]-lowbit(pos[i]))...中查找有多少个数比小于等于x,记为t2,则1到pos[i]中节点总数减t2就得到前缀比x[i]大的,小于等于x的总数(可以通过树状数组查询 ask(c,val) )-t2就是后缀里比x小的,然后更新pos[i],pos[i]+lowbit(pos[i]).....这些平衡树,给被删除的节点打上标记(--siz即可),同时在原树状数组里x[i]位置上加上-1.

#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
,pos
;
vector<int>vec
;
int c
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息