POJ2299 线段树求逆序数
来源:互联网 发布:2016人工智能论坛 编辑:程序博客网 时间:2024/06/05 11:27
题意:
将一个无序的序列排成有序的最小步数,该算法通过交换两个相邻的序列元素来处理n个不同的整数序列,直到序列按升序排序。
思路:
就是求序列逆序数,我的方法用线段树求解(我的逆序数模板可能跟其他大佬有一丢丢不同可以看一下这个线段树简述)。
具体:
将一个序列一个一个列出来,看“排在它前面元素有多少个比他大的”。
线段树节点的权值value表示区间[left,right]此时已经有多少个元素,所以插入一个元素X,只要知道(查询)区间(X+1,N)里有多少个元素即可,就是上面所说的“排在它前面元素有多少个比他大的”。
细节:
但是得用元素下标来求逆序数(因为ai最大999,999,999;具体操作见代码),这样缩小区间最大值。
就只需要建树BuildTree(1,1,N+1),注意是1到N+1。
栗子:
num[i].x 9 1 0 5 4 (逆序数1+2+1+2 = 6)
num[i].pos 1 2 3 4 5
排序后
num[i].x 0 1 4 5 9
num[i].pos 3 2 5 4 1 (逆序数1+0+1+4 = 6)真巧啊,逆序数居然是一样的(>^v^<)
插入2:查询Query(1,3,6)得到[3,6]区间此时有几个元素,并更新UpdateTree(father[2]),
插入5:查询Query(1,6,6)得到[5,6]区间此时有几个元素,并更新UpdateTree(father[5]),
依次。。。
插入
代码:
#include <stdio.h>#include <iostream>#include <cstring>#include <stdlib.h>#include <math.h>#include <algorithm>#include <queue>//#include <bits/stdc++.h>using namespace std;const int maxn = 1<<20;const int N = 500000+5;struct Node { int value; int left, right;};int father[N];struct s { int x, pos;}num[N];Node node[N*4];void BuildTree(int i, int left, int right){ node[i].left = left; //写入第i个结点的左区间 node[i].right = right; //写入第i个结点的右区间 node[i].value = 0; //区间权值初始化为0 if(left == right) { father[left] = i; //知道每个点对应的序号(结点的下标) return; } //建立左子树 BuildTree(i<<1, left, (left+right)/2); //建立右子树 BuildTree((i<<1)+1, (left+right)/2+1, right);}bool cmp(s a, s b){ return a.x < b.x;}void UpdateTree(int ri){ if(ri == 0) return; //已找到祖先 node[ri].value++; UpdateTree(ri/2); //递归更新,有父节点往上找}long long sum;void Query(int i, int l, int r){ if(node[i].left == l && node[i].right == r) { sum += node[i].value; return; } i = i << 1; if(l <= node[i].right) { //左区间有涉及 if(r <= node[i].right) //全包含于左区间,则查询形态不变 Query(i, l, r); else //半包含于左区间,则查询区间拆分,左端点不变,右端点变为左区间的右孩子端点 Query(i, l, node[i].right); } i += 1; if(r >= node[i].left) { //右区间有涉及 if(l >= node[i].left) //全包含于右区间,则查询形态不变 Query(i, l, r); else //半包含于右区间,则查询区间拆分 Query(i, node[i].left, r); }}int main(){ //freopen("in.txt", "r", stdin); int n; while(scanf("%d", &n), n) { memset(num, 0, sizeof(num)); long long ans = 0; for(int i = 1; i <= n; i++) { scanf("%d", &num[i].x); num[i].pos = i; } sort(num+1, num+n+1, cmp); BuildTree(1, 1, n+1); for(int i = 1; i <= n; i++) { sum = 0; UpdateTree(father[num[i].pos]); Query(1, num[i].pos+1, n+1); ans += sum; } printf("%I64d\n", ans); } return 0;}
阅读全文
0 0
- poj2299-------------线段树求逆序数
- POJ2299 线段树求逆序数
- poj2299(逆序数+线段树)
- 线段树求逆序数方法 HDU1394&&POJ2299
- POJ2299 归并求逆序数
- 线段树---求逆序数
- 线段树求逆序数
- 线段树--求逆序数
- POJ2299 归并排序求逆序数
- POJ2299 树状数组求逆序数
- poj2299 - Ultra-QuickSort (求逆序数)
- 树状数组求逆序数poj2299
- poj2299 归并排序求逆序数
- poj2299 归并排序求逆序数
- poj2299--归并排序求逆序数
- POJ2299 树状数组求逆序数
- POJ2299 树状数组求逆序数
- poj2299 树状数组快速求逆序数
- ValueError: Cannot feed value of shape (1,) for Tensor u'Placeholder:0', which has shape '(1, 1)'
- 装配一个对象 dataSource 对象 spring 火推03
- PC浏览器播放m3u8
- K分类算法
- 面向对象编程有三大特性:封装、继承、多态。
- POJ2299 线段树求逆序数
- Qt组件之模拟电池充电
- git拉一个新分支
- 线性表类型定义与顺序表操作
- 二叉搜索树(二叉穿线树)抽象结构以及线索化算法
- visual studio C++ 使用OpenMP 进行并行计算
- 蓝桥杯 算法提高 快乐司机
- 感知机模型
- OPENGL学习笔记之九