您的位置:首页 > 其它

bzoj3295 [Cqoi2011]动态逆序对

2018-01-06 12:21 429 查看

3295: [Cqoi2011]动态逆序对

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 6119 Solved: 2142
[Submit][Status][Discuss]

Description

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

Input

输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。

Output

输出包含m行,依次为删除每个元素之前,逆序对的个数。

Sample Input

5 4

1

5

3

4

2

5

1

4

2

Sample Output

5

2

2

1

样例解释

(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

HINT

N<=100000 M<=50000

分析:cdq分治比较裸的题目.考虑i,j如何才能构成逆序对:Ti < Tj,Xi < Xj,Yi > Yj.其中T是cdq分治中的时间,X是下标,Y是大小.因为题目只涉及到删除操作,那么可以用一个很常用的方法:时间倒流来处理.每增加一个点,看T ≤ mid的点中有多少x比它大并且y比它小的点,和x比它小并且y比它大的点.因为每次不光是要计算原先被删除的点构成的逆序对,还要算序列中剩下的数的逆序对.那么一开始将序列初始化为空序列,对每一个元素分配一个T,代表插入的时间,其中没有被删除的点要先分配,这样就能做到统计答案不遗漏了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const int maxn = 100010;
int n,m,pos[maxn],T;
ll ans[maxn],c[maxn],Ans;

struct node
{
int id,x,y;
}e[maxn],p[maxn];

bool cmp(node a,node b)
{
if (a.x == b.x && a.y == b.y)
return a.id < b.id;
if (a.x == b.x)
return a.y < b.y;
return a.x < b.x;
}

void add(int x,int v)
{
while (x <= n)
{
c[x] += v;
x += x & (-x);
}
}

ll query(int x)
{
ll res = 0;
while (x)
{
res += c[x];
x -= x & (-x);
}
return res;
}

void solve(int l,int r)
{
if (l == r)
return;
int mid = (l + r) >> 1;
for (int i = l; i <= r; i++)
{
if (e[i].id <= mid)
add(e[i].y,1);
else
ans[e[i].id] += query(n) - query(e[i].y);
}
for (int i = l; i <= r; i++)
if (e[i].id <= mid)
add(e[i].y,-1);
for (int i = r; i >= l; i--)
{
if (e[i].id <= mid)
add(e[i].y,1);
else
ans[e[i].id] += query(e[i].y);
}
for (int i = r; i >= l; i--)
if (e[i].id <= mid)
add(e[i].y,-1);
int L = l,R = mid + 1;
for (int i = l; i <= r; i++)
{
if (e[i].id <= mid)
p[L++] = e[i];
else
p[R++] = e[i];
}
for (int i = l; i <= r; i++)
e[i] = p[i];
solve(l,mid);
solve(mid + 1,r);
}

int main()
{
scanf("%d%d",&n,&m);
T = n;
for (int i = 1; i <= n; i++)
{
scanf("%d",&e[i].y);
e[i].x = i;
pos[e[i].y] = i;
}
for (int i = 1; i <= m; i++)
{
int k;
scanf("%d",&k);
e[pos[k]].id = T--;
}
for (int i = 1; i <= n; i++)
if (!e[i].id)
e[i].id = T--;
sort(e + 1,e + 1 + n,cmp);
solve(1,n);
for (int i = 1; i <= n; i++)
Ans += ans[i];
for (int i = n; i > n - m; i--)
{
printf("%lld\n",Ans);
Ans -= ans[i];
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: