大致题意: 给定一个序列(a_i),每次把(isim n)中小于等于(a_i)的数排序并放回原位置,求所有操作前及每一操作后的逆序对个数。
性质
众所周知,排序的题目中必然有许多有趣的性质。
我们定义一个数的贡献为它为较大值的逆序对个数。
可以发现,根据此题的排序方式,不被排序的数与被排序的数之间的相对大小是不变的,也就是说,不被排序的数的贡献不会被改变。
而所有被排序的数,由于小于它的数必然都到了它的前面,因此贡献相当于被清零了。
线段树
求初始贡献可以直接用树状数组,然后我们还需要一个数据结构,能实现对一段区间内小于等于某数的数进行修改。
乍一看,两重限制,似乎是树套树?
实际上, 由于每次修改是清零,因此每个数只需被修改一次即可。
那么,如果我们每次清零时同时给这个位置上的高度赋一个极大值,就能够保证每个位置只被修改一次。
于是,只要用线段树就能维护了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
#define LL long long
using namespace std;
int n,a[N+5],s[N+5],dc,dv[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
');}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class SegmentTree//线段树
{
private:
#define PT CI l=1,CI r=n,CI rt=1
#define LT l,mid,rt<<1
#define RT mid+1,r,rt<<1|1
#define PU(x) (O[x].V=O[x<<1].V+O[x<<1|1].V,O[x].H=min(O[x<<1].H,O[x<<1|1].H))
struct node {LL V;int H;}O[N<<2];
public:
I void Build(PT)//建树
{
if(l==r) return (void)(O[rt].V=s[l],O[rt].H=a[l]);
int mid=l+r>>1;Build(LT),Build(RT),PU(rt);
}
I void U(CI s,CI x,PT)//修改
{
if(l==r) return (void)(O[rt].V=0,O[rt].H=dc+1);int mid=l+r>>1;//清零的同时赋一个极大值
s<=mid&&O[rt<<1].H<=x&&(U(s,x,LT),0),O[rt<<1|1].H<=x&&(U(s,x,RT),0),PU(rt);//如果存在小于等于x的数就去修改
}
I LL Q() {return O[1].V;}//询问整个序列和
}S;
struct TreeArray//树状数组
{
int v[N+5];I void U(RI x) {W(x<=dc) ++v[x],x+=x&-x;}//修改
I int Q(RI x,RI t=0) {W(x) t+=v[x],x-=x&-x;return t;}//询问
}T;
int main()
{
RI Qt,i,x;for(F.read(n),F.read(Qt),i=1;i<=n;++i) F.read(a[i]),dv[i]=a[i];
for(sort(dv+1,dv+n+1),dc=unique(dv+1,dv+n+1)-dv-1,i=n;i;--i)//离散化
a[i]=lower_bound(dv+1,dv+dc+1,a[i])-dv,s[i]=T.Q(a[i]-1),T.U(a[i]);//求初始贡献
S.Build(),F.writeln(S.Q());W(Qt--) F.read(x),S.U(x,a[x]),F.writeln(S.Q());//每次将被排序的数贡献清零
return F.clear(),0;
}