hdu 1394(线段树)

来源:互联网 发布:掌趣上游网络牟正文 编辑:程序博客网 时间:2024/05/22 05:04


这道题目是求逆序数的。要得到答案,需要利用一个结论,如果是0到n-1 的排列,那么如果第一个数放到最后,这与这个数列,逆序数减少a[i],增加n-a[i]-1;


隔了几天之后,再做这道题目,发现有点生疏了。

在题目中的数字是从 0--n-1的。因此在初始化的时候要 build( 0,n-1 ,1)

在query 函数里,是查询a[i]到n-1 一段区间里面的逆序数。


time 62ms#include <iostream>#include <stdio.h>#include <algorithm>using namespace std;const int N=5005;int sum[N<<2];int a[N];void push_up(int rt){  sum[rt]=sum[rt<<1]+sum[rt<<1|1] ; }void build(int l,int r,int rt){    sum[rt]=0;    if(l==r) return ;    int m=(l+r)>>1;    build(l,m,rt<<1);    build(m+1,r,rt<<1|1);}void updata(int l,int r,int rt,int p){   if(l==r)   {   sum[rt]++;       return ;   }   int m=(l+r)>>1;   if(p<=m)      updata(l,m,rt<<1,p);   else      updata(m+1,r,rt<<1|1,p);   push_up(rt);}int query(int l,int r,int rt,int s,int t){   if(s<=l&& t>=r)   {       return sum[rt];   }   int m=(l+r)>>1;   int ret=0;   if(s<=m)       ret+=query(l,m,rt<<1,s,t);   if(t>m)       ret+=query(m+1,r,rt<<1|1,s,t);   return ret;}int main(){   int n;   while(~scanf("%d",&n))   {        int ans=0;        build(0,n-1,1);        for(int i=0;i<n;i++)        {            scanf("%d",&a[i]);            ans+=query(0,n-1,1,a[i],n-1);            updata( 0,n-1,1,a[i] );        }        int ret=ans;        for(int i=0;i<n;i++)        {           ans=(ans-a[i] )+ (n-a[i]-1) ;           ret=min(ret,ans );        }        printf("%d\n",ret);    }}

在使用zkw 线段树的做法的时候,时间减少到了46ms;

贴上代码



#include <iostream>#include <stdio.h>#include <algorithm>#include <memory.h>using namespace std;const int N=5005;int T[N<<2];int M;void push_up(int n){    T[n]=T[n<<1]+T[n<<1|1];}void updata(int n){    for(T[n+=M]+=1,n>>=1;n;n>>=1)        push_up(n);}int query(int s,int t){    int ans=0;    for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1)    {        if(~s&1)  ans+=T[s^1];        if( t&1)  ans+=T[t^1];    }    return ans;}int a[N];int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        for(M=1;M<=n+1;M<<=1);        int sum=0;        memset(T,0,sizeof(T));        for(int i=0;i<n;i++)        {            scanf("%d",&a[i]);            a[i]++;  <span style="font-family: 'Courier New'; white-space: pre-wrap; color: rgb(0, 128, 0); line-height: 1.5 !important;">//</span><span style="font-family: 'Courier New'; white-space: pre-wrap; color: rgb(0, 128, 0); line-height: 1.5 !important;">注意后面add的时候不能在0位置上add</span>            if(a[i]!=n)                sum+=query(a[i]+1,n);            updata(a[i]);        }        int ret=sum;        for(int i=0;i<n;i++)        {            sum=sum+(n-a[i])-(a[i]-1);            ret=min(ret,sum);        }        printf("%d\n",ret);    }}


0 0