26天以前做过的一道题,之前的做法是分治预处理,树套树在线修改,复杂度为O(nlogn+m*logn*logn),代码量较大。
本来想学习一下cdq分治的,看到论文上的凸包、斜率就暂时放一边了,只知道和一般的分治的不同是左子问题可以用来解决右边的子问题。
今天下午YY了一个离线的分治做法。
对于每一个数字,构成逆序对除了val大小还和被删除的时间del有关,这实际上是一个三维偏序的问题。
一个元素是一个三元组e(pos,val,del),e1和e2对答案有贡献当且仅当e1.pos < e1.pos && e1.val > e2.val && e1.del > e2.del。
第一维pos已经给好了,第二个维度就用归并,而第三个维度就用树状数组(BIT)。
用BIT的想法来源于,BIT插入的顺序对于着之前都已经满足的序,在这里就是已经满足e1.pos < e1.pos && e1.val > e2.val ,
然后用del查询就可以得到满足第三个条件e1.del > e2.del的元素个数。
思想如此,实现上有还值得注意的地方,一是BIT插入的值域范围不能太大,所以我记录了两个关于时间的信息tKth[],tRank[],
tKth[i]表示当前区间第i大的del,tRank[del]表示del在当前区间的名次,(名次从1开始,0表示没有删去),可以很方便地用归并去维护。
二是BIT只能查询小的,需要转化。总对数是容易得到的,用总对数去减就好了。
复杂度依然是O(nlogn+m*logn*logn),但常数很小,代码量也不大。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5+5, maxm = 1e5+5; ll ans; int iv_pir[maxn], a[maxn], tRank[maxn], tKth[maxn]; int del[maxn], temp[maxn]; int C[2][maxn]; int qry[maxm]; #define lb(x) (x&-x) void add(int C[],int x,int d,int range) { //if(x<1) return; while(x <= range){ C[x] += d; x += lb(x); } } int sum(int C[],int x) { int re = 0; while(x>0){ re += C[x]; x -= lb(x); } return re; } void divide(int l,int r) { if(l == r) { if(del[a[l]]) { tKth[l] = del[a[l]]; } return; } int mid = (l+r)>>1; divide(l, mid); divide(mid+1, r); //conquer int p = l, q = mid+1, k = 0; while(p <= mid && !tKth[p]) { temp[k++] = 0; p++; } while(q <= r && !tKth[q]) { temp[k++] = 0; q++; } int base = l+k-1; while(p<=mid || q<=r){ if(p>mid || (q<=r && tKth[p] > tKth[q])) { temp[k++] = tKth[q++]; }else { temp[k++] = tKth[p++]; } } memcpy(tKth+l,temp,sizeof(int)*k); for(int i = base+1; i <= r; i++){ tRank[tKth[i]] = i-base; } int sz = r-base; memset(C[0]+1,0,sizeof(int)*(sz)); memset(C[1]+1,0,sizeof(int)*(sz)); for(int i = l; i <= mid; i++) { if(del[a[i]]) add(C[0],tRank[del[a[i]]],1,sz); } p = l, q = mid+1, k = 0; while(p<=mid || q<=r){ if(p>mid || (q<=r && a[p] > a[q])) { ans += mid-p+1; if(del[a[q]]){ iv_pir[a[q]] += mid-p+1 - sum(C[0], tRank[del[a[q]]]); add(C[1], tRank[del[a[q]]], 1, sz); } temp[k++] = a[q++]; }else { if(del[a[p]]){ iv_pir[a[p]] += q-mid-1 - sum(C[1], tRank[del[a[p]]]); add(C[0], tRank[del[a[p]]], -1, sz); } temp[k++] = a[p++]; } } memcpy(a+l, temp, sizeof(int)*k); } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int n, m; ; while(~scanf("%d%d", &n, &m)){ for(int i = 0; i < n; i++) scanf("%d", a+i); memset(del+1,0,sizeof(int)*n); for(int i = 1; i <= m; i++) { scanf("%d", qry+i); del[qry[i]] = i; iv_pir[qry[i]] = 0; } ans = 0; divide(0,n-1); for(int i = 1; i <= m; i++){ printf("%lld\n", ans); ans -= iv_pir[qry[i]]; } } return 0; }
UVA 11990 ``Dynamic'' Inversion
时间: 2024-10-29 03:47:48