树状数组 逆序对变形 2017HZAU现场赛G-Sequence Number

来源:互联网 发布:mac相簿照片如何导出 编辑:程序博客网 时间:2024/06/09 16:18

题目链接:http://acm.hzau.edu.cn/problem.php?cid=1029&pid=6

题意:给你n个数(1<=N<=50000 ),每个数 Ai (1<=Ai<=10^9)。求给你的数列中正序对的最大长度。两个数的长度是两个数序号的差。

题解:因为给的数的范围比较大,所以要先离散化一下。然后用树状数组维护一下每个数前面的最小的数的序号,最后取最大即可。具体见代码注释。

#include <bits/stdc++.h>using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 5e4+5;int c[maxn],n,mmin[maxn];struct node{    int value,index;  //value值,index该值的序号};node sz[maxn];bool cmp(node a,node b)  //sort按node中value的值升序排序{    return a.value<b.value;}int lowbit(int x){    return x&(-x);}void update(int x,int value){    while(x<=n)    {        mmin[x] = min(mmin[x],value);  //mmin[x]表示x前面的数的最小值的序号        x += lowbit(x);    }}int query(int x){    int ans = INF;    while(x>0)    {        ans = min(mmin[x],ans);        x -= lowbit(x);    }    return ans;   //ans=x前面的数的最小值的序号}int main(){    while(~scanf("%d",&n))    {        int tmp;        for(int i=1;i<=n;i++)        {            scanf("%d",&tmp);            sz[i].value=tmp;            sz[i].index=i;        }        memset(mmin,INF,sizeof(mmin));        sort(sz+1,sz+n+1,cmp);        for(int i=1;i<=n;i++)        {            c[sz[i].index] = i;  //离散化数列,把数列中的数离散化为1-n。            //把1-n按node升序填到原先数的序号中            //比如:5,2,555,52,999,10            //离散化后:2,1,5,4,6,3        }        int ans=-1;        for(int i=1;i<=n;i++)        {            update(c[i],i);            tmp = query(c[i]);            if(tmp!=INF)            {                tmp = i-tmp;            }            ans = max(ans,tmp);        }        printf("%d\n",ans);    }    return 0;}

这题要多看看才能理解,特别是把给的数列的数离散化为1-n,然后再用树状数组维护最小序号的思想。

其实这题可以暴力过,但是不推荐。因为这只是数据没弄好,不然肯定不能暴力过。

之前我还写过用归并排序求逆序对个数的方法,然而到这题里面就不好求序号之间的差了。比赛的时候这题我没过,所以最好还是掌握一下用树状数组求逆序的方法。

0 0