|  | 
				
					
	
		
		
		题目链接: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; 
  }   |