版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/er111er/article/details/84675358
题目链接:
Click here
Solution
设
表示
与它后面的数形成的逆序对个数。
为原来数列逆序对个数。
每次询问一个
,对于满足
并且
的所有
,若
并且
,那么
形成了逆序对。但由于
,所以这些
都会被排好序,变成了
并且
,这些
的逆序对也就全都被消去了,也就是说
要减去这些
。
直接上树套树orCDQ?不存在的。因为一个
在某一次询问被消去影响之后,就不会再被消去,所以在线的做法没法做。那么考虑离线,按照询问的修改位置排序,询问
能够消去位置
的影响的条件是
且
。设
表示
是第几个询问,那么
最早消去影响的时间就是满足
且
的最小的
。
这是个二维偏序问题,按照
排序后一维被消掉,条件
用树状数组维护后缀最小值即可。
至于当询问
对应的
被某个询问
修改的情况,我们只需要用原来没被修改过的的
即可,因为如果
被
改了,说明
后面的逆序对早就被询问
消完了,我们即使把这个询问加进去也不会影响答案。
然后此题完。
Code
由于using namespace std
被ban掉了,为了巩固基础知识,我自己实现了归并排序、离散化、二分等算法,导致码量大了一点,但是让我对基础算法理解加深了更多。
#include <cstdio>
#include <cstring>
#include <cstdlib>
typedef long long ll;
const int N = 100007;
const ll INF = 0x3f3f3f3f;
int min(int a, int b) { return a < b ? a : b; }
int n, m, len, a[N], val[N], arr[N], temp[N];
ll sum[N];
struct note { int po, tim, val; } q[N], tmp[N];
int operator<(note a, note b) { return a.po < b.po; }
void sortq(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
sortq(l, mid), sortq(mid + 1, r);
int i = l, j = mid + 1, len = 0;
while (j <= r)
{
while (i <= mid && q[i] < q[j]) tmp[++len] = q[i++];
tmp[++len] = q[j++];
}
while (i <= mid) tmp[++len] = q[i++];
for (int i = 1; i <= len; i++) q[l + i - 1] = tmp[i];
}
void sort(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
sort(l, mid), sort(mid + 1, r);
int i = l, j = mid + 1, len = 0;
while (j <= r)
{
while (i <= mid && arr[i] <= arr[j]) temp[++len] = arr[i++];
temp[++len] = arr[j++];
}
while (i <= mid) temp[++len] = arr[i++];
for (int i = 1; i <= len; i++) arr[l + i - 1] = temp[i];
}
void unique()
{
len = 0;
int i = 1;
while (i <= n)
{
arr[++len] = arr[i++];
while (i <= n && arr[i] == arr[i - 1]) i++;
}
}
int lower_bound(int val)
{
int l = 1, r = len, mid, ans;
while (l <= r)
{
mid = l + r >> 1;
if (arr[mid] >= val) r = mid - 1, ans = mid;
else l = mid + 1;
}
return ans;
}
int tr[N][2];
void add(int po, int k, int v)
{
for (; po <= n; po += (po & (-po)))
{
if (k) tr[po][k] = min(tr[po][k], v);
else tr[po][k] += v;
}
}
int query(int po, int k)
{
int ret = k ? INF : 0;
for (; po; po -= (po & (-po)))
{
if (k) ret = min(ret, tr[po][k]);
else ret += tr[po][k];
}
return ret;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", a + i);
memcpy(arr, a, sizeof(a));
sort(1, n);
unique();
for (int i = n; i >= 1; i--) a[i] = lower_bound(a[i]), val[i] = query(a[i] - 1, 0), add(a[i], 0, 1), sum[0] += val[i];
for (int i = 1; i <= m; i++) scanf("%d", &q[i].po), q[i].tim = i, q[i].val = a[q[i].po];
sortq(1, m);
for (int i = 1; i <= n; i++) tr[i][1] = INF;
for (int i = 1, j = 1; i <= n; i++)
{
while (j <= m && q[j].po <= i) add(len - q[j].val + 1, 1, q[j].tim), j++;
int ret = query(len - a[i] + 1, 1);
if (ret < INF) sum[ret] -= val[i];
}
printf("%lld\n", sum[0]);
for (int i = 1; i <= m; i++) sum[i] += sum[i - 1], printf("%lld\n", sum[i]);
return 0;
}