HDU 2688 Rotate(树状数组---求正序数)

Problem Description
Recently yifenfei face such a problem that give you millions of positive integers,tell how many pairs i and j that satisfy F[i] smaller than F[j] strictly when i is smaller than j strictly. i and j is the serial number in the interger sequence. Of course, the problem is not over, the initial interger sequence will change all the time. Changing format is like this [S E] (abs(E-S)<=1000) that mean between the S and E of the sequece will Rotate one times.
For example initial sequence is 1 2 3 4 5.
If changing format is [1 3], than the sequence will be 1 3 4 2 5 because the first sequence is base from 0.

Input
The input contains multiple test cases.
Each case first given a integer n standing the length of integer sequence (2<=n<=3000000)
Second a line with n integers standing F[i](0<F[i]<=10000)
Third a line with one integer m (m < 10000)
Than m lines quiry, first give the type of quiry. A character C, if C is ‘R’ than give the changing format, if C equal to ‘Q’, just put the numbers of satisfy pairs.

Output
Output just according to said.

Sample Input
  
  
5 1 2 3 4 5 3 Q R 1 3 Q

Sample Output
  
  
10 8
题目大意:给你一个n个数(1到n且不重复)的全排列,求这n个数的正序数(序号比前面大,值也比前面大),然后给出个区间,这个区间顺时针循环转一次。比如,输入R 1 3,下标(从0开始)为1到3的数顺时针循环一次,即(2 3 4 变成3 4 2)其余不动,所以1 2 3 4 5变成 1 3 4 2 5.当输入Q时,输出当前排列的正序数。
思路分析:这是一个动态区间更新,求总和问题。由于题目给出是1-n的全排列。所以与求逆序数不同,不要离散化。直接求出正序数即可。更新过程中继续判断.
复杂度为n*logN.具体解释 见AC代码。这道题用C++ 提交600MS ,不知为什么一用G++就超时。可能判定系统问题吧。
#include<stdio.h>
#include<string.h>
int a[3000005];
int c[10005];
int n;
int lowbit(int x)
{
    return x&(-x);
}
void updata(int x,int d)
{
    while(x<=10005)   /*这点我也是不明白,开始写出 while(x<=n) WA 了无数次 后来才明白题目有这样一句话:Second a line with n integers standing F[i](0<F[i]<=10000),您明白了吗?*/

    {
        c[x]=c[x]+d;
        x=x+lowbit(x);
    }
}
int getsum(int x)
{
    int res = 0;
    while(x>0)
    {
        res=res+c[x];
        x=x-lowbit(x);
    }
    return res;
}
int main()
{
    int m,i;
    char s[10];
    int x,y,t;
    __int64 ans;
    while(scanf("%d",&n)!=EOF)
    {
        memset(a,0,sizeof(a));
        memset(c,0,sizeof(c));
        ans = 0;
        for(i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            updata(a[i],1);
            ans=ans+getsum(a[i]-1);     //前a[i]-1个数都比a[i]小,计算总和
        }
        scanf("%d",&m);
        while(m--)
        {
            scanf("%s",s);
            if(s[0]=='Q')
                printf("%I64d\n",ans);
            else
            {
                if(s[0]=='R')
                {
                    scanf("%d%d",&x,&y);
                    x++;        //下标从1开始的
                    y++;
                    t=a[x];
                    for(i=x; i<y; i++)
                    {
                        //移位过程中,只是a[x]到了a[y]位置,其他都往前进1.相当于没动
                        //所以,只要把其他数跟a[x]比较即可。
                        a[i]=a[i+1];
                        if(a[i]>t)
                            ans--;
                        if(a[i]<t)
                            ans++;
                    }
                    a[y]=t;
                }
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值