用线段树求逆序数。。。 突然发现自己的单点更新以及自己区间查询还是有点问题。,。

这里先统一一下单点更新以及区间查询问题吧  统一使用全局变量 

区间查询的话 目的区间用全局变量x y表示 然后从第一层开始 不断向下层搜(也就是不断的二分的过程)

先说说平时怎么求逆序数把  在每次读入一个数的时候 记录前面比他大的数就是目前的逆序数

那么 怎么用线段树来实现呢 首先 我们需要建一个空树 每个节点记录这个区间里面出现数的个数(sum)然后再按顺序读入数列的时候 查询在读入这个数之前有多个个比他大的数 即查询(x+1,n-1)这个区间有多少值 然后单点更新刚读入的值

#include<cstdio>
#include<string.h>
#include<iostream>
#define maxn 5001
using namespace std;
struct node
{
    int l,r,sum;
}stu[maxn*4];
int n;
int arr[maxn];
int x,y;
void build(int l,int r,int i)
{
    stu[i].l=l;
    stu[i].r=r;
    stu[i].sum=0;
    if(l==r) return;
    int mid=(l+r)/2;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
}
int que(int i)
{
    if(x<=stu[i].l&&stu[i].r<=y)    return stu[i].sum;
    int mid=(stu[i].l+stu[i].r)/2;
    int sum1=0,sum2=0;
    if(x<=mid) sum1=que(i*2);
    if(y>mid) sum2=que(i*2+1);
    return sum1+sum2; 
}
void updata(int i)
{
    int l=stu[i].l;
    int r=stu[i].r;
    if(l==r)
    {
        stu[i].sum++;
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid) updata(i<<1);
    else updata(i<<1|1);
    stu[i].sum=stu[i*2].sum+stu[i*2+1].sum;
}
int main()
{
    while(cin>>n)
    {
        build(0,n-1,1);
        int sum=0;
        for(int i=0;i<n;i++) 
        {
            cin>>arr[i];
            x=arr[i];
            y=n-1;
            sum+=que(1);//统计每次插入时候的逆序数
            updata(1);
        }
        int ans=sum;
        for(int i=0;i<n;i++)
        {
            sum=sum+n-2*arr[i]-1;
            /*
              因为序列为[0, n-1],若最前面一个数为x,序列中比x
              小的数为[0, x-1], 共x个,比x大的数为[x+1, n-1],
              共n-x-1个,将x移到最后,比x小的数的逆序数均减1,
              x的前面比x大的数有n-x-1个,x的逆序数增加n-x-1。
              所以新序列的逆序数为原序列的逆序数加上n-2*x-1。
            */

if(ans>sum) ans=sum; } cout<<ans<<endl; } return 0;
posted @ 2016-08-10 20:28  猪突猛进!!!  阅读(183)  评论(0编辑  收藏  举报