您的位置:首页 > 其它

UVA 11990 ``Dynamic'' Inversion (序列分治)

2015-11-03 20:46 274 查看
26天以前做过的一道题,之前的做法是分治预处理,树套树在线修改,复杂度为O(nlogn+m*logn*logn),代码量较大。

本来想学习一下cdq分治的,看到论文上的凸包、斜率就暂时放一边了,只知道和一般的分治的不同是左子问题可以用来解决右边的子问题。

今天下午YY了一个离线的分治做法,也不知道叫不叫cdq。

Analysis:

对于每一个数字,构成逆序对除了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的元素个数。

Note:

思想如此,实现上有还值得注意的地方,一是BIT插入的值域范围不能太大,所以我记录了两个关于时间的信息tKth[],tRank[],

tKth[i]表示当前区间第i大的del,tRank[del]表示del在当前区间的名次,(名次从1开始,0表示没有删去),可以很方便地用归并去维护。

二是BIT只能查询小的,需要转化。总对数是容易得到的,用总对数去减就好了。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: