hdu2688 Rotate(树状数组)

来源:互联网 发布:华云数据集团有限公司 编辑:程序博客网 时间:2024/04/30 22:37

Rotate

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2867    Accepted Submission(s): 633


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
51 2 3 4 53QR 1 3Q
 
Sample Output
10
8

题意:

给定一个长度为 n 的数组F[], 求数组的顺序对(即当 i < j 时, 满足F[i] < F[j](严格递增))的数量?在访问的同时,会对数组进行旋转操作(循环左移一位)。
数据说明:
2 <= n <= 3000000
m <= 10000
0 < F[i] <= 10000
操作
R S E 将指定区间(S+1, E)(abs(E - S)<= 1000)进行循环左移一位的操作
Q 询问当前状态下这个数组的顺序对

思路:

1.用树状数组(暴力,T(n) = O(n * m),显然超时)反向求出最初状态的顺序对, T(n) = O(n * lgn)
2.对于旋转操作:循环处理F[s + 1] ~ F[e]与F[s]的关系, 这是因为我们通过观察可以发现,每次移位只是把区间内的第一个数换到最后一个位置,其他直接进行移位,这样看来我们只需要考虑F[s]与其他位置的大小关系,如果是F[s] 较大,那么说明是他的是顺序对, 直接累加一次, 否则减一操作,每次移位T(n) = O(1000 * m)
3.对于询问操作:直接输出数量即可, T(n) = O(1)

注意:

这道题我的代码有些问题,原因至今不明。
1. 将__int64换位 long long 就超时,不是很懂, 都是64bits。
2.将操作数组str的大小改成非2的幂次就很容易超时.
据学长说这是因为编译器的问题。
大家找到真正的原因,请告知 !
某一博客原文:这题卡常数卡的有点紧,要注意常数优化,还有就是HDOJ的稳定性不是很好,同一个代码有时能过,有时不能过

AC代码:

#include<stdio.h>#include<stdlib.h>#include<string.h>using namespace std;const int maxn = 1e4 + 10;const int maxm = 3e6 + 10;typedef __int64 LL;LL C[maxn];int ans[maxm];inline int lowbit(int x)// 判断最右边1的位置{    return x & (-x);}void Add(int pos)// 更新c[i]的值{    while(pos < maxn)    {        C[pos] ++;        pos += lowbit(pos);    }}LL Sum(int pos)// 求和c[1]+...+c[x]{    LL sum = 0ll;    while(pos > 0)    {        sum += C[pos];        pos -= lowbit(pos);    }    return sum;}int main(){    int n, m;    while(scanf("%d", &n) != EOF)    {        for(int i = 1; i < maxn; i ++) C[i] = 0ll;        LL val = 0ll;        for(int i = 0; i < n; i ++)        {            scanf("%d", &ans[i]);            val += Sum(ans[i] - 1);            Add(ans[i]);        }        scanf("%d", &m);        while(m --)        {            char str[4];            scanf("%s", str);            if(str[0] == 'Q')                printf("%I64d\n", val);            else            {                int s, e;                scanf("%d%d", &s, &e);                if(s > e)                {                    int tmp = s;                    s = e;                    e = tmp;                }                int v = ans[s];                for(int i = s; i < e; i ++)                {                    ans[i] = ans[i + 1];                    if(v < ans[i + 1]) val --;                    if(v > ans[i + 1]) val ++;                }                ans[e] = v;            }        }    }    return 0;}

0 0