线段树解Insertion Sort Advanced Analysis

题目出处

题意描述:

这个题目提问的是,在插入排序的序列给定的情况下,求最少需要移动的次数。

序列的长度n <=10^5

序列中的元素a[i] <=10^6

一组数据中case数t <=5

题目分析:

这个题,拿到题目一眼望去满满的都是暴力的影子(又傻逼了)。

然后仔细分析一下暴力的复杂度,每插入一个元素都要扫过一边数组,显而易见的O(n*n),TLE思密达。

然后再认真分析一下题目,所求最少的移动次数,也就是说:对于其中任意一个元素a[i],只需要求出从a[1]到a[i-1]中大于a[i]的数字的数量。

说白了就是逆序数。。。

之后就是寻找一种数据结构或者算法可以在o(n)更短的时间内求出逆序数

动手:

线段树和树状数组十分适合这题,于是研习一下百度搜到的神牛的代码,迅速山寨了一个线段树的代码。

 

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <cstring>
  7 using namespace std;
  8 
  9 const int MAXN = 1000000+5;
 10 
 11 struct Node{
 12     int a,b,left,right,val;
 13 };
 14 
 15 Node tree[MAXN*2];
 16 int L = 0;
 17 int a[100000+5];
 18 
 19 void B( int x, int y ){
 20     //cout<<x<<"  "<<y<<endl;
 21     int This = L;
 22     tree[This].a = x;
 23     tree[This].b = y;
 24     tree[This].val = 0;
 25     if ( y - x >= 1 ){
 26         int mid = (x+y)/2;
 27         L++;
 28         tree[This].left = L;
 29         B(x,mid);
 30         L++;
 31         tree[This].right = L;
 32         B(mid+1,y);
 33     }
 34     //cout<<"DONE "<<x<<" "<<y<<endl;
 35 }
 36 
 37 void I( int x, int y, int t ){
 38     //cout<<"I "<<x<<" "<<y<<" "<<t<<endl;
 39     if ( ( x <= tree[t].a ) && ( y >= tree[t].b ) ){
 40         tree[t].val++;
 41     }else{
 42         tree[t].val++;
 43         int mid = (tree[t].a+tree[t].b)/2;
 44         if ( x <= mid ){
 45             I(x,y,tree[t].left);
 46         }
 47         if ( y >= mid+1 ){
 48             I(x,y,tree[t].right);
 49         }
 50     }
 51 }
 52 
 53 int S( int x, int y, int t ){
 54     if ( tree[t].val == 0 ){
 55         return 0;
 56     }
 57     if ( ( x<= tree[t].a )  && ( y >= tree[t].b ) ){
 58         return tree[t].val;
 59     }else{
 60     int mid = (tree[t].a+tree[t].b)/2;
 61     int ans = 0;
 62     if ( x <= mid ){
 63         ans += S(x,y,tree[t].left);
 64     }
 65     if ( y >= mid+1 ){
 66         ans += S(x,y,tree[t].right);
 67     }
 68     return ans;
 69     }
 70 }
 71 
 72 int G( int x, int y ){
 73     return S(0,y,0)-S(0,x,0);
 74 }
 75 
 76 void show(int k){
 77     for ( int i = 0; i<= k; i++ ){
 78     cout<<i<<" f "<<tree[i].a<<" t "<<tree[i].b<<"  "<<tree[i].left<<"  "<<tree[i].right<<"  "<<tree[i].val<<endl;
 79 }
 80 }
 81 
 82 void solve(){
 83     int n;
 84     cin>>n;
 85     int i = 0;
 86     int MAX = 0;
 87     long long ans = 0;
 88     int MIN = 1000000+10;
 89     memset(a,0,sizeof(a));
 90     for ( i = 0; i < n; i++ ){
 91         cin>>a[i];
 92         if ( MAX < a[i] ){
 93             MAX = a[i];
 94         }
 95         if ( MIN > a[i] ){
 96             MIN = a[i];
 97         }
 98     }
 99     //cout<<MAX<<endl;
100     //cout<<MIN<<endl;
101     B(MIN-1,MAX);
102     //show(L);
103     //cout<<"sb"<<endl;
104     for ( i = 0; i < n; i++ ){
105         I(a[i],a[i],0);
106         ans += G(a[i],MAX);
107     }
108     cout<<ans<<endl;
109 }
110 
111 
112 int main() {
113     int t;
114     int i;
115     cin>>t;
116     for ( i = 0; i <t; i++ ){
117         L = 0;
118         solve();
119     }
120     return 0;
121 }
线段树

 

 

 

想起来个要命的事儿就是用python3写会超时,可能是python内部开内存的方式比较慢,不像C++写在外面,是直接开出来的。

这题后来拿给狗哥做了一发,结果用了个树状数组就给我平了,,,虽然差不大多,但是代码量要小很多,看来需要研习一下了。

posted @ 2013-09-19 10:47  qoshi  阅读(279)  评论(0编辑  收藏  举报