洛谷P1908 逆序對 - 樹狀數組 - 離散化
阿新 • • 發佈:2018-08-26
nbsp 更新 get == can 逆序對 nod string 對應關系
一種離散化方法,把序列的離散化地只保留相對大小
sort(a+1, a+n+1, cmp); for(int i=1; i<=n; i++) { if(i == 1 || a[i].val != a[i-1].val) { tot++; } b[a[i].ord] = tot; }
註意,tot即使不累加,b數組仍然會更新,這就保證了a數組每個元素都和原來集合有對應關系,並且sort不穩定的問題也避免了
還有一種離散化,要求去重,那麽保存下輸入序號,進行去重操作後對新集合進行按序號地排序
bool cmp1(node x, node y) { return x.val < y.val; } bool cmp2(node x, node y) { return x.ord < y.ord; } sort(a+1, a+n+1, cmp1); for(int i=1; i<=n; i++) { if(i == 1 || a[i] != a[i-1]) { b[++tot] = a[i]; } } sort(b+1, b+tot+1, cmp2);
倒序枚舉?逆序對可以等價地看為有哪些數排在我後面還比我小,倒序就可以找排在後面的,然後按以其值為坐標,插入值為1,插入樹狀數組。
由於從後往前插入,按目前值為坐標查詢,他前面的數一定在他後面還比他小,前綴和即答案
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 500000 + 10; long long n,tree[MAXN],ans,tot,b[MAXN]; struct node{ long long ord,val; }a[MAXN]; void add(long long p, long long x) { while(p <= n) { tree[p] += x; p += (p&-p); } } int getsum(long long p) { long long sum = 0; while(p) { sum += tree[p]; p -= (p&-p); } return sum; } bool cmp(node x, node y) { return x.val < y.val; } int main() { scanf("%lld", &n); for(int i=1; i<=n; i++) { scanf("%lld", &a[i].val); a[i].ord = i; } sort(a+1, a+n+1, cmp); for(int i=1; i<=n; i++) { if(i == 1 || a[i].val != a[i-1].val) { tot++; } b[a[i].ord] = tot; } for(int i=n; i; i--) { add(b[i], 1); ans += getsum(b[i]-1); } printf("%lld", ans); return 0; }
洛谷P1908 逆序對 - 樹狀數組 - 離散化