目录
显示
题目链接
https://www.luogu.com.cn/problem/P6186
题解
设 \(s_i=\sum_{j=1}^{i-1}[p_j \gt p_i]\)。
容易发现逆序对数就等于 \(\sum_{i=1}^n s_i\)。
这是没有排序的情况,经过一次排序后,逆序对数会怎样变化呢?
一个显然的事实是,一次冒泡排序后,设 \(p_j\) 为 \([1,i-1]\) 区间内最大的元素(且有 \(p_j \gt p_i\)),那么 \(p_j\) 一定会交换到 \(p_i\) 后面,而 \(p_i\) 会向前移动一位。
从而可以得到一个结论:对于那些满足 \(s_i \gt 0\) 的 \(i\),经过一次排序后会有 \(s_i=\max\{s_{i+1}-1,0\}\)。
这样,假如经历了 \(k\) 轮冒泡排序,只有那些满足 \(s_i \gt k\) 的 \(s_i\) 才能产生贡献(剩下的都变成零了)。
答案当然是:
$$\sum_{s_i \gt k}s_i -\sum_{s_i \gt k}k$$
这个可以用两个树状数组来维护。
修改操作就比较简单了。分类讨论邻位交换后 \(s_i\) 的变化情况即可。
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
struct BIT
{
long long a[200005];
int lowbit(int x)
{
return x&(-x);
}
void init()
{
memset(a,0,sizeof(a));
}
void add(int x,int y)
{
if(x==0)return;
while(x<=n)
{
a[x]+=y;
x+=lowbit(x);
}
}
long long query(int x)
{
long long ans=0;
while(x)
{
ans+=a[x];
x-=lowbit(x);
}
return ans;
}
}tr1,tr2;
int a[200005],b[200005];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=tr1.query(n)-tr1.query(a[i]);
tr1.add(a[i],1);
}
tr1.init();
for(int i=1;i<=n;i++)
tr1.add(b[i],1),tr2.add(b[i],b[i]);
while(m--)
{
int op,x;
cin>>op>>x;
if(op==1)
{
if(a[x]>a[x+1])
{
tr1.add(b[x+1],-1),tr2.add(b[x+1],-b[x+1]);
b[x+1]--;
tr1.add(b[x+1],1),tr2.add(b[x+1],b[x+1]);
}
else
{
tr1.add(b[x],-1),tr2.add(b[x],-b[x]);
b[x]++;
tr1.add(b[x],1),tr2.add(b[x],b[x]);
}
swap(a[x],a[x+1]),swap(b[x],b[x+1]);
}
else
{
if(x>=n)cout<<0<<endl;
else
{
long long res1=(tr1.query(n)-tr1.query(x))*x;
long long res2=tr2.query(n)-tr2.query(x);
cout<<res2-res1<<endl;
}
}
}
return 0;
}