Codevs 1688 求逆序對(權值線段樹)
阿新 • • 發佈:2017-09-02
per wrapper oid tdi nod 時間限制 cti 一個 sca
輸出描述 Output Description
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個數。
所有逆序對總數.
樣例輸入 Sample Input4
3
2
3
2
樣例輸出 Sample Output3
/* 首先我們更改線段樹葉子節點處存儲的內容,將其更改為權值,並且記錄對於一個權值x的個數。那麽我們首先構建一棵空樹,對於每次插入的數字x,我們查找x+1到max區間的數字存在的個數,並將這個個數加入答案,然後插入這個數字。最後輸出答案就可以了。。 */ #include<iostream> #include<cstdio> usingnamespace 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(intk,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 求逆序對(權值線段樹)