既然是區間操作 我們想到了線段樹
我們先建立乙個空樹 然後呢 按照這個序列的順序將每個值插入 ,每次插入伴隨一次查詢 查詢前面插入的比這次插入的大的數字的個數
然後就可以了 複雜度 nlogn 可以接受
題意:就是給出一串數,當依次在將第乙個數變為最後乙個數的過程中,要你求它的最小逆序數。
思路:可以用樹狀陣列和線段數做。這裡我是用線段樹做的。建的是一棵空樹,然後每插入乙個點之前,統計大於這個數的有多少個,直到所有的數都插入完成,就結果了逆序樹的統計。
要得出答案主要是利用了乙個結論,如果是0到n的排列,那麼如果把第乙個數放到最後,對於這個數列,逆序數是減少a[i],而增加n-1-a[i]的.當然,你也可以是統計小於這個數的有多少個,然後再用已經插入樹中i個元素減去小於這個數的個數,得出的結果也是在一樣的。
#include #include #include #include #include #include #include #include #define inf 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const long long mod = 1e9 + 7;
const int maxn = 55555;
using namespace std;
typedef long long ll;
int sum[maxn<<2];
void pushup(int rt)
void build(int l,int r,int rt)
int m=(l+r)>>1;
build(lson);
build(rson);
// pushup(rt);
}void update(int p,int l,int r,int rt)
int m=(l+r)>>1;
if(p<=m)update(p,lson);
else update(p,rson);
pushup(rt);
}int query(int l,int r,int l,int r,int rt)
int m=(l+r)>>1;
int ret=0;
if(l<=m)ret+=query(l,r,lson);
if(r>m)ret+=query(l,r,rson);
return ret;
}int x[maxn];
int main()
int ret = sum;
for (int i = 1 ; i <= n ; i ++)
printf("%d\n",ret);
}return 0;
}
線段樹 求逆序數
hdu1394 minimum inversion number 題意 求inversion後的最小逆序數 思路 用o nlogn 複雜度求出最初逆序數後,就可以用o 1 的複雜度分別遞推出其他解 線段樹功能 update 單點增減 query 區間求和 逆序數 對於 n個不同 的元素,先規定各元素...
逆序數和線段樹的關係
考慮一下逆序數的定義 分別是 2,1 4,3 4,1 3,1 也就是說針對乙個數。判斷在這個序列中這個數字置後面的數有多少個比它小。也就是說針對乙個數。判斷在這個序列中這個數字置之前有多少個數比它大。那就是詢問當前數 n 區間上的出現了多少個數。由於我們詢問順序是從前到後 左到右 所以在當前數前面且...
線段樹或樹狀陣列求逆序數
線段樹或樹狀陣列求逆序數 求逆序數的方法有分治,歸併,本文只介紹線段樹或樹狀陣列求逆序數的辦法,眾所周知,線段樹和樹狀樹可以用來解決區間操作問題,就是因為這兩個演算法區間操作的時間複雜度很低o logn 才讓這種方法具有可行性。首先先來看乙個序列 6 1 2 7 3 4 8 5,此序列的逆序數為5 ...