水上由岐有一个长为n 的序列a1; a2; : : : ; an。接下来她要进行m 次操
作。对于第k 次操作,她会指定jk,然后取出所有i ≥ jk 且ai ≤ ajk 的ai,
将它们从小到大排序后按顺序重新放回之前的位置(只有这些数的顺序可能改
变,其它数的位置不变)。
定义一个逆序对(i; j) 为满足i < j 且ai > aj 的一个二元组。第一次操作
前和每次操作结束后,她都想要知道当前序列有多少个逆序对。
任务描述
输入
第一行,两个正整数n; m。
第二行,n 个正整数a1; a2; : : : ; an,保证1 ≤ ai ≤ n,可能存在相同值。
第三行,m 个正整数j1; j2; : : : ; jm,保证1 ≤ jk ≤ n。
输出
第一行,第一个整数表示操作前的逆序对数量,接下来m 个整数表示每次
操作后的逆序对数量。
样例数据
输入
6 2
1 3 4 2 6 1
2 3
输出
6 3 1
解释
第一次操作:由1 3 4 2 6 1 变为1 1 4 2 6 3。
第二次操作:由1 1 4 2 6 3 变为1 1 2 3 6 4。
每次重新排序的数的逆序对数变为0,而其他位置的逆序对数不改变。
所以用树状数组处理出最开始每个位置的逆序对数。(倒着for,每个位置的逆序对数:这个位置以后小于等于它的数。)
然后每次找出需重新排序的数,用线段数找区间最小值,找到后把那个位置对应的值修改为inf.
这样就再也不会找重复了。
#include<bits/stdc++.h>
using namespace std;
long long f[800010], zhi[200005];
int n, m,a[200005],b[200005];
void read(long long &x)
{
x = 0;
char c = getchar();
while(c < '0' ||c > '9')
{
c = getchar();
}
while(c < '0' && c > '9')
{
x = x * 10 + c - '0';
c = getchar();
}
}
struct node
{
int wei;
long long f;
};
node q[800005];
long long qurey(long long x)
{
long long rt = 0;
for(int i = x; i; i -= i&-i)
{
rt += f[i];
}
return rt;
}
void modify(int a,int b)
{
for(int i = a; i <= n; i += i&-i)
{
f[i] += b;
}
}
void build(int o,int l,int r)
{
int mid = (l + r) /2;
q[o].f = 1e18;
if(l == r) return;
build(o*2,l,mid);
build(o*2+1,mid+1,r);
}
void update(int o)
{
if(q[o*2].f < q[o*2+1].f)
{
q[o] = q[o*2];
}
else
q[o] = q[o*2+1];
}
void modify1(int o, int l, int r, int pos, long long val)
{
if(l == r)
{
q[o].f= val;
q[o].wei = pos;
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) modify1(o*2, l, mid, pos, val);
if(pos > mid) modify1(o*2+1, mid + 1, r, pos, val);
update(o);
}
node qurey1(int o, int l, int r, int ql,int qr)
{
if(ql <= l && r <= qr)
{
return q[o];
}
int mid = (l + r) >> 1;
node rt, he, ha;
rt.f = 1e18;
if(ql <= mid)
{
he = qurey1(o*2,l,mid,ql,qr);
if(he.f < rt.f)
{
rt = he;
}
}
if(mid < qr)
{
ha = qurey1(o*2+1, mid+1, r, ql, qr);
if(ha.f < rt.f)
{
rt = ha;
}
}
return rt;
}
int main()
{
long long ans = 0;
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d%d",&n,&m);
build(1,1,n);
for(int i = 1; i <= n; i++)
scanf("%lld",&a[i]);
for(int i = n; i >= 1; i--)
{
b[i] = qurey(a[i]-1);
ans += b[i];
modify1(1,1,n,i,a[i]);
modify(a[i],1);
}
cout <<ans<< " " ;
for(int i = 1; i <= m; i++)
{
int l, cnt = 0;
long long ans1 = 0;
scanf("%d",&l);
while(1)
{
node ha = qurey1(1,1,n,l,n);
if(ha.f > a[l]) break;
ans1 += b[ha.wei];
modify1(1,1,n,ha.wei,1e9);
}
ans -= ans1;
if(i != m)
printf("%lld ", ans);
else printf("%lld",ans) ;
}
return 0;
}