刚考完,赶紧来水一波题解
一、题目
二、解法
首先这道题有一道同名题,很相似(推荐先看这道同名题的题解,那题是黑的,怎么这题评成蓝色了?)
逆序对转化成每一个数前面比它大的数的个数(记为
b
b
b数组),如果一个数前面有比他大的数,那么它会左移一位,也就是
b
b
b减
1
1
1,那么答案为(记轮数为
k
k
k):
∑
min
(
b
[
i
]
−
k
,
0
)
\sum \min(b[i]-k,0)
∑min(b[i]−k,0)
很容易发现用权值线段树维护吧,分成大于 k k k的部分和小于等于 k k k的部分,算大于 k k k部分的贡献即可,至于修改,只交换 x x x和 x + 1 x+1 x+1,显然对其它的位置是没有任何影响的,讨论一下然后在权值线段树上修改就行了。
图方便我写的树状数组,时间复杂度 O ( n log n ) O(n\log n) O(nlogn),代码在民间数据能够通过,并且我这个小蒟蒻还是觉得打的是对的,可以放心看 q w q qwq qwq。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
const int M = 200005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,a[M],b[M],bit[M];
ll k,sum[M],A,B;
int lowbit(int x)
{
return x&(-x);
}
void upd(int x)
{
for(int i=x;i<=n;i+=lowbit(i))
bit[i]++;
}
int ask(int x)
{
int res=0;
for(int i=x;i>=1;i-=lowbit(i))
res+=bit[i];
return res;
}
void modify(int x,int f)
{
for(int i=x+1;i<=n;i+=lowbit(i))
{
bit[i]+=f;
sum[i]+=x*f;
}
}
void query(int x)
{
for(int i=x+1;i>=1;i-=lowbit(i))
{
A+=bit[i];
B+=sum[i];
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
b[i]=i-ask(a[i])-1;
k+=b[i];
upd(a[i]);
}
memset(bit,0,sizeof bit);
for(int i=1;i<=n;i++)
{
modify(b[i],1);
}
for(int i=1;i<=m;i++)
{
int op=read(),x=read();
if(op==1)
{
if(a[x]>a[x+1])
{
swap(a[x],a[x+1]);
swap(b[x],b[x+1]);
modify(b[x],-1);
b[x]--;k--;
modify(b[x],1);
}
else if(a[x]<a[x+1])
{
swap(a[x],a[x+1]);
swap(b[x],b[x+1]);
modify(b[x+1],-1);
b[x+1]++;k++;
modify(b[x+1],1);
}
}
else
{
if(x>=n)
{
puts("0");
continue ;
}
A=0;B=0;
query(x);
ll ans=(k-B)-(n-A)*x;
printf("%lld\n",ans);
}
}
}