线段树求解Minimum Inversion Number

题:Minimum Inversion Number

题意:给出一个序列,如果某一项比它前面的项小(本来应该是一次增大的),这就是一组逆序项,如例:1 3 6 9 0 8 5 7 4 2就有22组逆序项。(1,0)(3,0)(3,2)(6,0)(6,5)(6,4)(9,0)(9,8)(9,5)。。。现在你可以将x1移至最后,再将x2移至最后,直到把xn-1移到最后(xn移到最后无意义),在这过程中,逆序项数目最少为多少?

分析:思路是先求出原序列的逆序项数目,再通过递推求出所有情况下逆序项数目。

先建立一棵空树,每段的sum都为0,输入每一项(如x1)时可查询树中已存在且比它大的数的个数(因为再它之前输入的是它前面的项),即这一项的逆序项的个数,再将这一项插入树中,更新树(为下次查询),一直到输入结束,此时累加起来的和即是这个序列的逆序项个数总和。然后递推求将所有情况下逆序项。记m为当前(原)序列的逆序项个数,将第一项x1移至最后时,此时逆序项个数为m-x1+((n-1)-x1),假设x1等于0,将0移到序列最后是原来的逆序项减去0(因为后面没有比0小的项),再加上((n-1)-0)(因为0放在最后时,0前面(n-1)个数都是逆序数),同理x2、x3、x4。。。

代码:

#include<cstdio>
#include<algorithm>
#define lson l, m, rt<<1
#define rson m + 1, r, rt<<1|1
using namespace std;

const int maxn = 5555;
int sum[maxn<<2];
int x[maxn];

void PushUP(int rt){
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
/********************************
建树,初始化sum值全为0,没有节点
*********************************/
void build(int l ,int r, int rt){
    sum[rt] = 0;
    if(l == r) return;
    int m = (r + l)>>1;
    build(lson);
    build(rson);
}
/******************************************
插入节点p,更新所有与p有关的sum
******************************************/
void update(int p, int l, int r, int rt){
    if(l == r){
        sum[rt]++;
        return;
    }
    int m = (l + r)>>1;
    if(p <= m) update(p, lson);
    else update(p, rson);
    PushUP(rt);
}
/*******************************************
查询L到R之间存在节点的个数
题意是查询大于L的数的个数,即默认R为n-1
*******************************************/
int query(int L, int R, int l, int r, int rt){
    if(L <= l && r <= R) return sum[rt];
    int m = (l + r)>>1;
    int ret = 0;
    if(L <= m) ret += query(L, R, lson);
    if(R > m) ret += query(L, R, rson);
    return ret;
}

int main(){
    int n;
    while(~scanf("%d", &n)){
        build(0, n - 1, 0);
        int m = 0;
        for(int i = 0; i < n; i++){
            scanf("%d", &x[i]);
            m += query(x[i], n - 1, 0, n - 1, 1);//计算初始序列所有逆序数的个数m
            update(x[i], 0, n - 1, 1);
        }
        int ans = m;
        for(int i = 0; i < n; i++){
            m += ((n - 1) - x[i]) - x[i];//当把x[i]移至最后,m会减少x[i],会增加((n - 1) - x[i])
            ans = min(ans, m);
        }
        printf("%d\n", ans);
    }
    return 0;
}

线段树求解Minimum Inversion Number

时间: 2024-11-10 01:18:21

线段树求解Minimum Inversion Number的相关文章

Hdu 1394 Minimum Inversion Number(线段树或树状数组)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11981    Accepted Submission(s): 7321 Problem Description The inversion number of a given number sequence a1, a2, ..., a

HDU 1394 Minimum Inversion Number(线段树:单点更新,求逆序数)

http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 14648    Accepted Submission(s): 8942 Problem Description The inversion n

HDU 1394 Minimum Inversion Number.(线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 ~~~~ 早起一发线段树,开心又快乐.这题暴力也能水过,同时线段树的效率也就体现的尤为明显了,看了大牛的博客,说是还可以用树状数组,点树和合并序列写,现在还不懂,留着以后在写吧. ~~~~ 大致题意:给定一个数字序列,同时由此可以得到n个序列, 要求从n个序列中找到逆序数最小的序列,输出最小逆序数. 首先介绍下逆序数的概念: 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面

hdu 1394 Minimum Inversion Number(这道题改日我要用线段树再做一次哟~)

Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of

HDU1394 Minimum Inversion Number 线段树+数学

Problem Description The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, -, an, if we move the first m >= 0 numbers to the end of the

HDOJ 1394 Minimum Inversion Number 求循环串的最小逆序数(暴力&amp;&amp;线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 14879    Accepted Submission(s): 9082 Problem Description The inversion number of a given number sequence a1, a2, ..., a

hdu 1394 Minimum Inversion Number(线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10853    Accepted Submission(s): 6676 Problem Description The inversion number of a given number sequence a1, a2, ..., a

Minimum Inversion Number(线段树单点更新+逆序数)

Minimum Inversion Number(线段树单点更新+逆序数) Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy

HDU 1394 Minimum Inversion Number(线段树求逆序数)

题目地址:HDU 1394 这题可以用线段树来求逆序数. 这题的维护信息为每个数是否已经出现.每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的.那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了.因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数.多的逆序数就是放到后面后前面比他大的数的个数.因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-