一道線段樹+樹狀陣列的題
阿新 • • 發佈:2018-12-17
水上由岐有一個長為n 的序列a1; a2; : : : ; an。接下來她要進行m 次操 作。對於第k 次操作,她會指定jk,然後取出所有i ≥ jk 且ai ≤ ajk 的ai, 將它們從小到大排序後按順序重新放回之前的位置(只有這些數的順序可能改 變,其它數的位置不變)。 定義一個逆序對(i; j) 為滿足i < j 且ai > aj 的一個二元組。第一次操作 前和每次操作結束後,她都想要知道當前序列有多少個逆序對。 任務描述 輸入 第一行,兩個正整數n; m。 第二行,n 個正整數a1; a2; : : : ; an,保證1 ≤ ai ≤ n,可能存在相同值。 第三行,m 個正整數j1; j2; : : : ; jm,保證1 ≤ jk ≤ n。 輸出 第一行,第一個整數表示操作前的逆序對數量,接下來m 個整數表示每次 操作後的逆序對數量。
樣例資料 輸入 6 2 1 3 4 2 6 1 2 3 輸出 6 3 1 解釋 第一次操作:由1 3 4 2 6 1 變為1 1 4 2 6 3。 第二次操作:由1 1 4 2 6 3 變為1 1 2 3 6 4。
每次重新排序的數的逆序對數變為0,而其他位置的逆序對數不改變。
所以用樹狀陣列處理出最開始每個位置的逆序對數。(倒著for,每個位置的逆序對數:這個位置以後小於等於它的數。)
然後每次找出需重新排序的數,用線段數找區間最小值,找到後把那個位置對應的值修改為inf.
這樣就再也不會找重複了。
#include<bits/stdc++.h> using namespace std; long long f[800010], zhi[200005]; int n, m,a[200005],b[200005]; void read(long long &x) { x = 0; char c = getchar(); while(c < '0' ||c > '9') { c = getchar(); } while(c < '0' && c > '9') { x = x * 10 + c - '0'; c = getchar(); } } struct node { int wei; long long f; }; node q[800005]; long long qurey(long long x) { long long rt = 0; for(int i = x; i; i -= i&-i) { rt += f[i]; } return rt; } void modify(int a,int b) { for(int i = a; i <= n; i += i&-i) { f[i] += b; } } void build(int o,int l,int r) { int mid = (l + r) /2; q[o].f = 1e18; if(l == r) return; build(o*2,l,mid); build(o*2+1,mid+1,r); } void update(int o) { if(q[o*2].f < q[o*2+1].f) { q[o] = q[o*2]; } else q[o] = q[o*2+1]; } void modify1(int o, int l, int r, int pos, long long val) { if(l == r) { q[o].f= val; q[o].wei = pos; return; } int mid = (l + r) >> 1; if(pos <= mid) modify1(o*2, l, mid, pos, val); if(pos > mid) modify1(o*2+1, mid + 1, r, pos, val); update(o); } node qurey1(int o, int l, int r, int ql,int qr) { if(ql <= l && r <= qr) { return q[o]; } int mid = (l + r) >> 1; node rt, he, ha; rt.f = 1e18; if(ql <= mid) { he = qurey1(o*2,l,mid,ql,qr); if(he.f < rt.f) { rt = he; } } if(mid < qr) { ha = qurey1(o*2+1, mid+1, r, ql, qr); if(ha.f < rt.f) { rt = ha; } } return rt; } int main() { long long ans = 0; freopen("count.in","r",stdin); freopen("count.out","w",stdout); scanf("%d%d",&n,&m); build(1,1,n); for(int i = 1; i <= n; i++) scanf("%lld",&a[i]); for(int i = n; i >= 1; i--) { b[i] = qurey(a[i]-1); ans += b[i]; modify1(1,1,n,i,a[i]); modify(a[i],1); } cout <<ans<< " " ; for(int i = 1; i <= m; i++) { int l, cnt = 0; long long ans1 = 0; scanf("%d",&l); while(1) { node ha = qurey1(1,1,n,l,n); if(ha.f > a[l]) break; ans1 += b[ha.wei]; modify1(1,1,n,ha.wei,1e9); } ans -= ans1; if(i != m) printf("%lld ", ans); else printf("%lld",ans) ; } return 0; }