看完之后可以关注我的新浪微博哦: @晨阳微光(虽然和ACM毫无关系)
题目类型:数据结构 线段树/平方分割 分桶法
复杂度:O(n*sqrt(n))
题目含义:
给出序列一个序列由n个数组成(这n个数互不相同)。
有m次询问,每次询问有一个值,进行的操作是减去序列中等于这个值的数,并输出在去掉这个值之前的这个序列的逆序数对
样例:5 4 (1,5,3,4,2) -> (1,3,4,2) -> (3,4,2) -> (3,2) -> (2)
1
5
3
4
2
5
1
4
2
问题分析及解法:关于序列S,如果将下标为i的数映射到二维坐标系上面的话,他的坐标为(i,S[i]),那么在坐标系上这个点左上和右下的点的个数之和就是这个数的逆序对个数。
解法就算是分桶法。
转载分桶法的理解:传送门
通过分桶法将平面分割为sqrt(n)*sqrt(n)。
每个桶维护两个信息:一是这个桶里的点的个数;二是同一行桶的个数的前缀和,用前缀和来做区域内的查询。
下面来看代码:
#include
#include
#define MAX_N 200016
#define MAX_M 100016
#define BUCKET_SIZE 450
using namespace std;
//
int n, m;
//
struct BUCKET
{
int cnt;//桶内有几个点
int prefix_sum;//这个桶之前(算这个)有多少个点,在这一行
}bucket[BUCKET_SIZE][BUCKET_SIZE];
struct SPACE
{
int X[MAX_N], Y[MAX_N];
void init() {
memset(X, -1, sizeof(X));
memset(Y, -1, sizeof(Y));
}
void insert(int x,int y) {
X[y] = x;
Y[x] = y;
}
void remove(int x, int y) {
X[y] = -1;
Y[x] = -1;
}
int getx(int y) {
return X[y];
}
int gety(int x) {
return Y[x];
}
}space;
//更新桶的前缀和
void updata_prefix_sum(int x, int y) {
int sum = (x > 0 ? bucket[x - 1][y].prefix_sum : 0);
for (int i = x; i < BUCKET_SIZE; i++) {
sum += bucket[i][y].cnt;
bucket[i][y].prefix_sum = sum;
}
}
//在平面区域加一个点
void add(int x,int y) {
space.insert(x, y);
int bucket_x = x / BUCKET_SIZE;
int bucket_y = y / BUCKET_SIZE;
bucket[bucket_x][bucket_y].cnt++;
updata_prefix_sum(bucket_x, bucket_y);
}
//在平面区域删除一个点
void remove(int x,int y) {
space.remove(x, y);
int bucket_x = x / BUCKET_SIZE;
int bucket_y = y / BUCKET_SIZE;
bucket[bucket_x][bucket_y].cnt--;
updata_prefix_sum(bucket_x, bucket_y);
}
//(0,0)到(x,y)有多少个点
int count_sum(int x,int y) {
int sum = 0;
int plane_x = (x + 1) / BUCKET_SIZE;
int plane_y = (y + 1) / BUCKET_SIZE;
for (int i = 0; i < plane_y; i++) {
if (plane_x > 0)sum += bucket[plane_x - 1][i].prefix_sum;
}
for (int i = plane_x*BUCKET_SIZE; i <= x; i++) {
if (space.gety(i) != -1 && space.gety(i) < plane_y*BUCKET_SIZE) {
sum++;
}
}
for (int i = plane_y*BUCKET_SIZE; i <= y; i++) {
if (space.getx(i) != -1 && space.getx(i) <= x) {
sum++;
}
}
return sum;
}
int count_r_sum(int x, int y) {
int r = 0;
int tmp = count_sum(x, y);
r += count_sum(n - 1, y) - tmp;
r += count_sum(x, n - 1) - tmp;
return r;
}
int main() {
while (cin >> n >> m) {
space.init();
memset(bucket, 0, sizeof(bucket));
long long result = 0;
for (int i = 0; i < n; i++) {
int num;
cin >> num;
add(i, num - 1);
result += count_r_sum(i, num - 1);
//cout<
<
> num;
num--;
cout << result << endl;
result -= count_r_sum(space.getx(num), num);
remove(space.getx(num), num);
}
}
return 0;
}