1. 程式人生 > 其它 >P1908 逆序對-線段樹題解

P1908 逆序對-線段樹題解

	讀完題目,你的第一想法肯定是直接暴力就能過了。實際上在看完資料之後。。。QAQ。好吧,肯定不能暴力,那
麼現在就要去尋找它的特徵。根據它的特徵,我們可以分析出要用線段樹去做這道題。那麼當我們確定這個演算法時,我
們就要找下一個難點:如何建立這個樹?這裡就直接告訴你叭:首先,我們要根據大小將初始陣列排列,然後再根據原
來的順序再排回來,然後根據每一個數的大小對號入座,在入座的過程中我們計算在這個葉子節點的右邊有多少個已經
入座的元素,這時候就體現出來了線段樹的便捷:查詢效率為O(log n) 級別。然後使用sum分別記錄,最後輸出sum。
/*
ID: erictian2018
TASK:
LANG: C++
*/
#include <iostream> #include <cstring> #include <string> #include <fstream> #include <algorithm> #include <queue> #include <stack> #include <iomanip> #include <math.h> #include <cmath> #include <ctime> #include <cstdio> #include
<map>
#define inf 0x7ffffff #define ll long long //#include <windows.h> //#include <bits/stdc++.h> using namespace std; /* 輸入: 6 5 4 2 5 3 1 輸出: */ ll scan() { ll x=0; ll flag=0; char ch=getchar(); while(ch<'0'||ch>'9') { ch=getchar(); if(ch=='-') flag=1; } for(; ch>='0'
&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; if(!flag) return x; return -x; } ll n; struct node{ ll l,r; ll cnt;cnt是指l到r有多少個元素 }tree[2000010]; ll sum;/求有多少個逆序對 struct st{ ll num,rank,order;//rk: 排序後的編號 }a[500100]; // bool cmp1(st a,st b){ if(a.num==b.num) return a.order<b.order; return a.num<b.num; } // bool cmp2(st a,st b){ return a.order<b.order; } // void build(ll l,ll r,ll k){ tree[k].l=l; tree[k].r=r; if(l==r) return ; ll mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); } // ll ask(ll l,ll r,ll k){ if(l<=tree[k].l&&tree[k].r<=r) return tree[k].cnt; ll mid=(tree[k].l+tree[k].r)/2; ll value=0; if(l<=mid) value+=ask(l,r,k*2); if(r>mid) value+=ask(l,r,k*2+1); return value; } // void change(ll l,ll r,ll k){ if(l==tree[k].l&&tree[k].r==r){ tree[k].cnt++; sum+=ask(l+1,n,1); return ; } ll mid=(tree[k].l+tree[k].r)/2; if(l<=mid) change(l,r,k*2); if(r>mid) change(l,r,k*2+1); tree[k].cnt=tree[k*2].cnt+tree[k*2+1].cnt; } int main() { //ofstream fout ("test.out"); //ifstream fin ("test.in"); n=scan(); for(ll i=1;i<=n;i++){ a[i].num=scan(); a[i].order=i; } //從小到大排序 如果有相同的數則下標較小的排在前面 sort(a+1,a+n+1,cmp1); for(ll i=1;i<=n;i++) a[i].rank=i; //根據order的下標再排回來 sort(a+1,a+n+1,cmp2); build(1,n,1); for(ll i=1;i<=n;i++) change(a[i].rank,a[i].rank,1); cout << sum << endl; return 0; }