題目
題解
在求整體的逆序對的數量時,很好辦,直接用樹狀數組處理即可,不過在這時,我們還需要處理出一個數組 ,其中 代表在區間 中滿足 的 有多少個。
然後我們再利用一個新的 ,並且倒着遍歷 數組,這樣我們可以處理出 數組,其中 表示在區間 中有多少 使得, 。
我們考慮刪除一個元素對答案的影響,刪除一個元素以後,那麼要從答案中減去這個元素原來能構成的逆序對的數量,也就是 。但是呀,這裏有一個問題!就是說 或者是 中很可能包含有已經被刪除掉的元素了。
解決這個問題有兩個方案,第一就是我們每刪除的一個元素就對所有依賴這個元素的 數組全部更新,這樣顯然不合理,遇到極端數據時間複雜度會爆炸。
還有一個解決方案就是,我們把要減去的部分容斥一下,即在已經被刪除的元素裏面,再找於、與 元素能構成逆序對的數量 。
這樣的話, 。
這個思路聽起來很完美,但是這個 要怎麼找呢?
其實我們需要的是對所有被刪除的元素建立一顆可修改的主席樹!
正常的主席樹想要修改的時候,如果修改了第 個版本的主席樹,同時要把 等版本的主席樹都修改,因爲是主席樹跟前一個版本的主席樹是有依賴關係的。
我們發現樹狀數組跟我們的需求非常像,因爲樹狀數組具有區間求和的性質,也具有單點修改時間複雜度 的優秀性質。
於是!我們可以用樹狀數組套權值線段樹來解決這個問題。
由於空間所限,我們做線段樹採用動態開點的方法。
其中樹狀數組裏的每一個節點裏麪包含有一顆線段樹。
代碼
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
#define pr(x) cout<<#x<<":"<<x<<endl
#define int long long
const int maxn = 200007;
struct segtree{
int root[maxn*40];
int lson[maxn*40];
int rson[maxn*40];
int val[maxn*40];
int idx;
void ins(int &rt,int l,int r,int pos,int v){
if(!rt) rt = ++idx;
val[rt] += v;
if(l == r) return ;
int mid = (l+r)/2;
if(pos <= mid) ins(lson[rt],l,mid,pos,v);
else ins(rson[rt],mid+1,r,pos,v);
}
int query(int rt,int l,int r,int ul,int ur){
if(!rt || r < ul || ur < l) return 0;
if(ul <= l && r <= ur) return val[rt];
int mid = (l+r)/2;
int a = query(lson[rt],l,mid,ul,ur);
int b = query(rson[rt],mid+1,r,ul,ur);
return a+b;
}
}seg;
struct BIT{
int a[maxn];
void add(int pos,int v){
for(;pos < maxn;pos += pos & (-pos))
a[pos] += v;
}
int query(int pos){
int ans = 0;
for(;pos;pos -= pos & (-pos))
ans += a[pos];
return ans;
}
}b1,b2;
int pos[maxn],a[maxn];
int pa[maxn],sa[maxn];
int n,m;
signed main(){
long long ans = 0;
cin>>n>>m;
for(int i = 1;i <= n;++i){
scanf("%lld",&a[i]);
pos[a[i]] = i;
b1.add(a[i],1);
ans += pa[i] = b1.query(n) - b1.query(a[i]);
}
for(int i = n;i > 0;i--){
sa[i] = b2.query(a[i]-1);
b2.add(a[i],1);
}
for(int i = 1;i <= m;++i){
printf("%lld\n",ans);
int v;scanf("%lld",&v);
int p = pos[v];p--;
long long tmp = 0;
for(;p;p -= p & (-p))
tmp += seg.query(seg.root[p],0,100001,v+1,100001);
p = pos[v];
for(;p;p -= p & (-p))
tmp -= seg.query(seg.root[p],0,100001,0,v-1);
p = n;
for(;p;p -= p & (-p))
tmp += seg.query(seg.root[p],0,100001,0,v-1);
ans -= sa[pos[v]] + pa[pos[v]] - tmp;
p = pos[v];
for(;p <= n;p += p&(-p))
seg.ins(seg.root[p],0,100001,v,1);
}
}