1. 程式人生 > >Codevs 1688 求逆序對(權值線段樹)

Codevs 1688 求逆序對(權值線段樹)

per wrapper oid tdi nod 時間限制 cti 一個 sca

1688 求逆序對

時間限制: 1 s 空間限制: 128000 KB 題目等級 : 黃金 Gold 題目描述 Description

給定一個序列a1,a2,…,an,如果存在i<j並且ai>aj,那麽我們稱之為逆序對,求逆序對的數目

數據範圍:N<=105。Ai<=105。時間限制為1s。

輸入描述 Input Description

第一行為n,表示序列長度,接下來的n行,第i+1行表示序列中的第i個數。

輸出描述 Output Description

所有逆序對總數.

樣例輸入 Sample Input

4

3

2

3

2

樣例輸出 Sample Output

3

/*
    首先我們更改線段樹葉子節點處存儲的內容,將其更改為權值,並且記錄對於一個權值x的個數。那麽我們首先構建一棵空樹,對於每次插入的數字x,我們查找x+1到max區間的數字存在的個數,並將這個個數加入答案,然後插入這個數字。最後輸出答案就可以了。。
*/
#include<iostream>
#include<cstdio>
using
namespace std; #define N 100010 int n; struct node{ int l,r; long long v; }tr[40010<<4]; void build(int k,int l,int r){ tr[k].l=l;tr[k].r=r; if(tr[k].l==tr[k].r)return; int mid=(l+r)>>1; build(k<<1,l,mid);build(k<<1|1,mid+1,r); } long long query(int
k,int l,int r){ if(tr[k].l>=l&&tr[k].r<=r)return tr[k].v; int mid=(tr[k].l+tr[k].r)>>1; long long res=0; if(l<=mid)res+=query(k<<1,l,r); if(r>mid)res+=query(k<<1|1,l,r); return res; } void Insert(int k,int l){ if(tr[k].l==l&&tr[k].r==tr[k].l){ tr[k].v++; return; } int mid=(tr[k].l+tr[k].r)>>1; if(l<=mid)Insert(k<<1,l); if(l>mid) Insert(k<<1|1,l); tr[k].v=tr[k<<1].v+tr[k<<1|1].v; } int main(){ scanf("%d",&n); build(1,1,N); int x; long long ans=0; for(int i=1;i<=n;i++){ scanf("%d",&x); ans+=query(1,x+1,N); Insert(1,x); } cout<<ans; return 0; }

Codevs 1688 求逆序對(權值線段樹)