|
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2688
/**//* 题意: 给定一串长度为N的序列(N <= 3000000),然后是M(M<=10000)个操作, 每个操作有两种形式: 1. Q 询问当前序列的顺序数 2. R S E (abs(E-S) <= 1000)将下标S到E的数列向左循环旋转一次
题解: 树状数组
思路: 经典问题,首先将N个数的顺序数用树状数组求出来,这个操作是nlogn 的,然后对于每次R操作,统计在[S+1,E]区间中比v[S]大的数和小的数的个数, 将之前的顺序数 - 比它大的数 + 比它小的数,更新这个值。然后顺序赋值即可。 Q操作只需要直接输出当前顺序数的值即可。 */
#include <iostream>
using namespace std;
#define maxn 10001 int ans[3000001]; int n, m;
#define ll __int64
ll c[maxn];
int lowbit(int x) { return x & (-x); }
void add(int pos) { while(pos < maxn) { c[pos] ++; pos += lowbit(pos); } }
ll sum(int pos) { ll s = 0; while(pos > 0) { s += c[pos]; pos -= lowbit(pos); } return s; }
int main() { int i; while(scanf("%d", &n) != EOF) { for(i = 1; i <= 10000; i++) c[i] = 0; ll val = 0; for(i = 0; i < n; i++) { scanf("%d", &ans[i]); val += sum(ans[i] - 1); add(ans[i]); } scanf("%d", &m);
while(m--) { char str[10]; 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; }
if(s != e) { int v = ans[s]; int lt = 0, bt = 0; for(i = s; i < e; i++) { ans[i] = ans[i+1]; if(v < ans[i+1]) { lt ++; } if(v > ans[i+1]) { bt ++; }
} ans[e] = v; val = val - lt + bt; } } } } return 0; }
|