1. 程式人生 > >逆序對+離散化

逆序對+離散化

學習了樹狀陣列就有了樹狀陣列的應用,求逆序對。

首先是如何求用樹狀陣列求逆序對,a陣列表示當前數字出現的次數,樹狀陣列維護當前數字每個數字之前數字有多少比它小的次數。。。描述的可能有誤感性理解一下就好。

add(a[i],1);

void add(int x,int y)
{
  for(;x<=n;x+=lowbit(x))c[x]+=y;
}

最後就是查詢當前數字之後有多少比它要小的數字的次數即可~

ans[i]=sum(a[i]-1);
int sum(int x)
{
    int tot=0;
    for(;x;x-=lowbit(x))tot+=c[x];
    
return tot; }

提交上去RE,為什麼呢?因為這裡的數字太大了,把一個數字當作陣列的下標,這是一件很危險的事情所以需要離散,

void discrete()
{
    sort(b+1,b+1+n);
    int m=unique(b+1,b+1+n)-b-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(b+1,b+m+1,a[i])-b;
}

這裡b[i]=a[i],程式碼具體什麼意思我也不是很懂具體就是這樣子操作就可以把b數組裡的數字一一對映到n上於是每個數字都不超過n。

還有要開long long 因為這個地方考慮最壞的情況最多的逆序對第n個數有n-1個逆序對,於是n個數字加起來是n^2的數量,炸int。

#include<iomanip>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
using namespace
std; inline long long read() { long long x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const long long maxn=500008; long long c[maxn],a[maxn],maxx=-1,ans[maxn],b[maxn]; long long n,m,tot=0; long long lowbit(long long x) { return x&(-x); } void add(long long x,long long y) { for(;x<=n;x+=lowbit(x))c[x]+=y; } void discrete() { sort(b+1,b+1+n); long long m=unique(b+1,b+1+n)-b-1; for(long long i=1;i<=n;i++) a[i]=lower_bound(b+1,b+m+1,a[i])-b; } long long sum(long long x) { long long tot=0; for(;x;x-=lowbit(x))tot+=c[x]; return tot; } int main() { // freopen("1.in","r",stdin); n=read(); for(long long i=1;i<=n;i++)a[i]=read(),b[i]=a[i]; discrete(); for(long long i=n;i>=1;i--) { add(a[i],1); ans[i]=sum(a[i]-1); } for(long long i=1;i<=n;i++)tot+=ans[i]; printf("%lld\n",tot); return 0; }
View Code

猝然臨之而不驚,無故加之而不怒~