nyoj 117 求逆序数【线段树 树状数组 归并排序】
来源:互联网 发布:盗梦空间limbo 知乎 编辑:程序博客网 时间:2024/05/29 06:43
求逆序数
时间限制:2000 ms | 内存限制:65535 KB
难度:5
- 描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
现在,给你一个N个元素的序列,请你判断出它的逆序数是多少。
比如 1 3 2 的逆序数就是1。
- 输入
- 第一行输入一个整数T表示测试数据的组数(1<=T<=5)
每组测试数据的每一行是一个整数N表示数列中共有N个元素(2〈=N〈=1000000)
随后的一行共有N个整数Ai(0<=Ai<1000000000),表示数列中的所有元素。
数据保证在多组测试数据中,多于10万个数的测试数据最多只有一组。 - 输出
- 输出该数列的逆序数
- 样例输入
221 131 3 2
- 样例输出
01
线段树lazy:1536ms
#include <cstdio>#include <cstring>#include <algorithm>#define MAX 1000000+10#define LL long longusing namespace std;int sum[MAX<<2];struct record{ int val, pos;}num[MAX];bool cmp(record a,record b){ if(a.val != b.val) return a.val > b.val; else return a.pos > b.pos;} void PushUp(int o){ sum[o] = sum[o<<1] + sum[o<<1|1];}void build(int o, int l, int r)//建树 { sum[o] = 0; if(l == r) return ; int mid = (l+r) >> 1; build(o<<1, l, mid); build(o<<1|1, mid+1, r); PushUp(o);}int query(int o, int l, int r, int L, int R)//查询 { if(L <= l && R >= r) { return sum[o]; } int mid = (l+r) >> 1; int res = 0; if(L <= mid) res += query(o<<1, l, mid, L, R); if(R > mid) res += query(o<<1|1, mid+1, r, L, R); return res;}void update(int o, int l, int r, int L)//更新 { if(l == r) { sum[o] += 1; return ; } int mid = (l+r) >> 1; if(L <= mid) update(o<<1, l, mid, L); else update(o<<1|1, mid+1, r, L); PushUp(o);}int main(){ int t, n, i; LL ans; scanf("%d", &t); while(t--) { scanf("%d", &n); build(1, 1 ,n); for(i = 0; i < n; i++) { scanf("%d", &num[i].val); num[i].pos = i + 1; } sort(num, num+n, cmp); ans = 0; for(i = 0; i < n; i++) { update(1, 1, n, num[i].pos); if(num[i].pos == 1) continue; ans += query(1, 1, n, 1, num[i].pos-1); } printf("%lld\n", ans); } return 0;}
线段树(不用lazy):1384ms
#include <cstdio>#include <cstring>#include <algorithm>#define MAX 1000000+10#define LL long longusing namespace std;int sum[MAX<<2];struct record{ int val, pos;}num[MAX];bool cmp(record a,record b){ if(a.val != b.val) return a.val > b.val; else return a.pos > b.pos;} void build(int o, int l, int r)//建树 { sum[o] = 0; if(l == r) return ; int mid = (l+r) >> 1; build(o<<1, l, mid); build(o<<1|1, mid+1, r);}int query(int o, int l, int r, int L, int R)//查询 { if(L == l && R == r) { return sum[o]; } int mid = (l+r) >> 1; if(R <= mid) return query(o<<1, l, mid, L, R); else if(L > mid) return query(o<<1|1, mid+1, r, L, R); else return query(o<<1, l, mid, L, mid) + query(o<<1|1, mid+1, r, mid+1, R);}void update(int o, int l, int r, int L)//更新 { sum[o] += 1; if(l == r) return ; int mid = (l+r) >> 1; if(L <= mid) update(o<<1, l, mid, L); else update(o<<1|1, mid+1, r, L); }int main(){ int t, n, i; LL ans; scanf("%d", &t); while(t--) { scanf("%d", &n); build(1, 1 ,n); for(i = 0; i < n; i++) { scanf("%d", &num[i].val); num[i].pos = i + 1; } sort(num, num+n, cmp); ans = 0; for(i = 0; i < n; i++) { update(1, 1, n, num[i].pos); if(num[i].pos == 1) continue; ans += query(1, 1, n, 1, num[i].pos-1); } printf("%lld\n", ans); } return 0;}
树状数组:1156ms
#include <cstdio>#include <cstring>#include <algorithm>#define LL long long#define MAX 1000000+10using namespace std;int n; int c[MAX<<2];struct record{ int val, pos;}num[MAX];bool cmp(record a,record b){ if(a.val != b.val) return a.val > b.val; else return a.pos > b.pos; }int lowbit(int x){ return x&(-x);}void update(int x){ while(x <= n) { c[x] += 1; x += lowbit(x); }}LL sum(int x){ LL s = 0; while(x > 0) { s += c[x]; x -= lowbit(x); } return s;}int main(){ int t; int i, j; LL ans; //int ans; scanf("%d", &t); while(t--) { scanf("%d", &n); memset(c, 0, sizeof(c)); for(i = 0; i < n; i++) { scanf("%d", &num[i].val); num[i].pos = i + 1; } sort(num, num+n, cmp); ans = 0; for(i = 0; i < n; i++) { update(num[i].pos); if(num[i].pos == 1) continue; ans += sum(num[i].pos - 1); } printf("%lld\n", ans); } return 0;}
归并排序:456ms
#include <cstdio>#include <cstring>#include <algorithm>#define MAX 1000000+10#define LL long longusing namespace std;int a[MAX], tmp[MAX];LL ans;void Merge(int l, int m, int r){ int i = l; int j = m + 1; int k = l; while(i <= m && j <= r) { if(a[i] > a[j]) { tmp[k++] = a[j++]; ans += m - i + 1; } else { tmp[k++] = a[i++]; } } while(i <= m) tmp[k++] = a[i++]; while(j <= r) tmp[k++] = a[j++]; for(int i = l; i <= r; i++) { a[i] = tmp[i]; }}void Merge_sort(int l,int r){ if(l < r) { int m = (l + r) >> 1; Merge_sort(l,m); Merge_sort(m+1,r); Merge(l,m,r); }}int main(){ int t, n; int i, j; LL res; scanf("%d", &t); while(t--) { scanf("%d", &n); for(i = 0; i < n; i++) { scanf("%d", &a[i]); } ans = 0; Merge_sort(0,n-1); printf("%lld\n", ans); } return 0;}
0 0
- nyoj 117 求逆序数【线段树 树状数组 归并排序】
- NYOJ 117 求逆序数 【树状数组】或【归并排序】
- NYOJ-117 求逆序数(树状数组或归并排序)
- ACM--归并排序&&树状数组--nyoj 117--求逆序数
- 归并求逆序数 树状数组求逆序数 线段树求逆序数
- 归并排序&&树状数组求逆序数
- 归并排序 树状数组 求逆序数
- [hdu]1394 Minimum Inversion Number -- 暴力求逆序、树状数组求逆序、线段树求逆序、归并排序求逆序
- NYOJ 117 求逆序数【归并排序求逆序数】
- 归并排序求逆序数 NYOJ 117
- NYOJ-117求逆序数【树状数组】
- NYOJ 117 求逆序数 【树状数组】
- nyoj 117 求逆序数【树状数组】
- 【树状数组or归并排序求逆序数】HDU 1394
- nyoj117求逆序数(离散化+树状数组/归并排序)
- 树状数组(归并排序) 之 求逆序数nyoj117
- 树状数组 和 归并排序 求逆序数
- 归并排序,树状数组,求逆序数 (openjudge 7662)
- 俄罗斯方块
- WORD VBA 操作WORD 文本框
- Unity客户端框架笔记(状态模式和策略模式在游戏中的应用)
- 参数化查询 但未提供该参数(将null插入数据库)
- codeforces 66 D. Petya and His Friends(数论)
- nyoj 117 求逆序数【线段树 树状数组 归并排序】
- java实现自动编号系统(类似于word中自动编号)
- Linux cp命令
- functor 是什么?
- LintCode-乱序字符串
- css与div的一些属性使用
- 6.12
- 二叉查找树的表示javascript
- 深入理解事务--Spring事务的传播机制