zoukankan      html  css  js  c++  java
  • UVA 11990 ``Dynamic'' Inversion (序列分治)

    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
    ", ans);
                ans -= iv_pir[qry[i]];
            }
        }
        return 0;
    }
  • 相关阅读:
    mysql数据恢复
    数据库备份脚本
    SHELL syntax error:unexpected end of file 提示错误
    shell script 的追踪与 debug
    mysql Host ‘XXXXXX’ is blocked because of many connection errors
    linux下MySQL 5.6源码安装
    C# 数据库并发的解决方案(通用版、EF版)
    Thread(线程)四
    C#线程系列讲座(1):BeginInvoke和EndInvoke方法
    在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4934340.html
Copyright © 2011-2022 走看看