D1T2 排队计划

Description:

对于一个序列 $h$,有 $m$ 次操作,每次操作 $j$ ,将 $p_j\le i\le n$中,小于等于第 $h_j$ 的元素取出并重排后插入。求每次操作后的逆序对的数量。

Solution:

一开始以为是个三维偏序

首先考虑暴力解法。对于每次询问重新求逆序对即可,预计时间复杂度为 $O(mnlogn)$ ,而且常数巨大。

然后考虑优化。可以观察到这次询问的答案可以从上一次的答案更新。易得对于每个取出的数 $h_i$ ,减少的逆序对的数量就是 $h_i$ 后比它小的数的个数。因为每次操作后序列都趋向有序,所以逆序对的数量会减少,单点暴力修改的时间复杂度是有保证的。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5e5+10;
const int inf=0x7fffffff;
#define in read()
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
int n,m,h[maxn],hsh[maxn],tot=0,x;
ll val[maxn];
struct node{
int pos,val;
}a[maxn];
struct BIT{
ll t[maxn];
inline int lowbit(int x){
return x&-x;
}
inline ll query(int x){
ll res=0;
while(x){
res+=t[x];
x-=lowbit(x);
}
return res;
}
inline void update(int x,ll val){
while(x<=tot){
t[x]+=val;
x+=lowbit(x);
}
}
}bit;
bool cmp(node a,node b){
//if(a.val==b.val) return a.pos<b.pos;
return a.val<b.val;
}

struct tree{
int l,r,pos;
}t[maxn<<2];
void pushup(int p){
if(hsh[t[p<<1|1].pos]<=hsh[t[p<<1].pos]) t[p].pos=t[p<<1|1].pos;
else t[p].pos=t[p<<1].pos;
}
void build(int l,int r,int p){
t[p].l=l;t[p].r=r;
if(l==r){
t[p].pos=l;
return ;
}
int mid=l+r>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
pushup(p);
}
void update(int l,int r,int p,int t){
if(l==r){
hsh[l]=inf;
val[l]=0;
return ;
}
int mid=l+r>>1;
if(t<=mid) update(l,mid,p<<1,t);
else update(mid+1,r,p<<1|1,t);
pushup(p);
}
int pd(int x,int y){
if(hsh[y]<=hsh[x]) return y;
return x;
}
int query(int l,int r,int p){
if(l<=t[p].l&&t[p].r<=r) return t[p].pos;
int ans=0;
int mid=t[p].l+t[p].r>>1;
if(l<=mid) ans=query(l,r,p<<1);
if(r>mid){
int t=query(l,r,p<<1|1);
if(!ans) ans=t;
else ans=pd(ans,t);
}
return ans;
}
int main(){
n=in;m=in;
for(int i=1;i<=n;i++){
a[i].pos=i;a[i].val=in;
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
if(a[i].val!=a[i-1].val) hsh[a[i].pos]=++tot;
else hsh[a[i].pos]=tot;
}
ll ans=0;
for(int i=n;i>=1;i--){
bit.update(hsh[i],1);
val[i]=bit.query(hsh[i]-1);
ans+=val[i];
}
printf("%lld\n",ans);
build(1,n,1);
for(int i=1;i<=m;i++){
x=in;
while(hsh[x]!=inf){
int t=query(x,n,1);
//cout<<"#debug "<<t<<endl;
ans-=val[t];
update(1,n,1,t);
}
printf("%lld\n",ans);
}
return 0;
}