1. 程式人生 > >洛谷P1908 逆序對 - 樹狀數組 - 離散化

洛谷P1908 逆序對 - 樹狀數組 - 離散化

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 逆序對 - 樹狀數組 - 離散化