CQOI2011 動態逆序對

2022-03-01 20:10:24 字數 1304 閱讀 1021

使用樹狀陣列求出初態下出f[i]、g[i]表示位置小(大)於i且值大(小)於a[i]的元素個數。顯然ans|初=sum f[i]=sum g[i]。

考慮第乙個刪去的點x,刪去以後,ans減少f[x]+g[x];再考慮第二個刪去的點y,刪去以後,ans減少f[y]+g[y]?不,f[y]、g[y]中可能算上了x(此題裡是必然),這這一對已經在上一次刪除時減掉了,所以ans減少f[y]+g[y]的同時,還應加上已刪除的點中與y構成的「逆序對數」。以後刪除的點同理;

假設當前正在刪除元素x,設元素到位置的對映為id[x],設f1、g1為在已刪的點中與x相比位置小(大)於i且值更大(小)於的點的個數,那麼ans應該為ans-f[x]-g[x]+f1+g1。現考慮如何快速計算f1、g1。以計算f1為例:

一:將刪除的點放在新序列b的相應位置,每次掃瞄b[1~id[x]]中有多少滿足b[i]>x的點。

二:不放將序列b擴充為矩陣b[i,j],b[i,j]表示位置為i,值為j的元素是否已經被刪除。每次n^2求矩陣b[1~id[x], x+1,n]的和

三:二中的b大小為n*n顯然不行。考慮將b[i]改為一顆權值線段樹(求一段值域內的元素個數),這樣大小變為nlogn。

四:每一次刪除乙個點,會修改線段樹b[id[x]n],用時過久。不放對所有權值線段樹的同乙個區間求字首和(例項:主席樹)查詢變為作差;這時修改線段樹b[id[x]n]相當於是單點修改更新字首和,考慮使用樹狀陣列來完成。

就是樹狀陣列套權值線段樹了。

#include using namespace std;

const int n=1e6+10;

int n,m,tot;

long long ans;

int root[n],bit[n],id[n],a[n],f[n],g[n];

struct edge t[n*30];

void update(int&x,int l,int r,int w)

int l[n],cntl,r[n],cntr;

int f1(int x,int y,int w) else

} return ret;

}int g1(int x,int y,int w)

void add(int x,int y)

int main()

for(int i=1; i<=n; ++i) bit[i]=0;

for(int i=n; i>=1; --i)

update(root[0],1,n,0);

for(int x; m--; )

} return 0;

}

Cqoi2011 動態逆序對

主席樹套樹狀陣列。主席樹第一題。鏈結靜態的逆序對問題很簡單,用線段樹或者是樹狀陣列即可解決。現在的問題是如何解決一道動態的逆序對問題?我們先把所有的逆序對統計出來。每次刪除數,我們可以把這個數對於逆序對個數的貢獻刪除出去。這個貢獻如何統計呢?front i 記錄i位置之前有多少個數比這個數大 bac...

CQOI2011 動態逆序對

這是一道cdq分治的好題,這道題的前置知識是cdq分治解決三維偏序問題,如果不會這個話請先自行學習。首先第乙個答案很顯然就是逆序對的數量,然後後面每次的刪除操作,我們考慮把這個被刪除的點原先的貢獻從答案中拿掉。我們用y表示這個點的數,del表示第幾個被刪除,若沒有被刪除則del m 1 考慮每個點的...

CQOI2011 動態逆序對

點此看題 考慮c dq cdqcd q,有三個值 t,d,v t,d,v t,d,v 要求t i t iti d i d idi v i vj v i v j vi vj 很容易看出來是三維偏序的板題,我們先保證t tt的有序,cdq cdqcd q的時候排序d dd,然後用樹狀陣列查詢v vv,貼...