【UVA, 11990】“Dynamic” Inversion【平方分割n】
2016-07-27 13:20
357 查看
看完之后可以关注我的新浪微博哦:
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/tongue.gif)
@晨阳微光(虽然和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)。
每个桶维护两个信息:一是这个桶里的点的个数;二是同一行桶的个数的前缀和,用前缀和来做区域内的查询。
下面来看代码:
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/tongue.gif)
@晨阳微光(虽然和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; }
相关文章推荐
- C#数据结构之顺序表(SeqList)实例详解
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 数据结构之Treap详解
- 用C语言举例讲解数据结构中的算法复杂度结与顺序表
- C#数据结构之堆栈(Stack)实例详解
- C#数据结构之双向链表(DbLinkList)实例详解
- JavaScript数据结构和算法之图和图算法
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- Java数据结构及算法实例:插入排序 Insertion Sort
- Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture
- java数据结构之java实现栈
- java数据结构之实现双向链表的示例
- Java数据结构及算法实例:选择排序 Selection Sort
- Java数据结构及算法实例:朴素字符匹配 Brute Force
- Java数据结构及算法实例:汉诺塔问题 Hanoi
- Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)