码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 11990 ``Dynamic'' Inversion

时间:2015-11-03 22:30:33      阅读:256      评论:0      收藏:0      [点我收藏+]

标签:

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

标签:

原文地址:http://www.cnblogs.com/jerryRey/p/4934340.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!