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

UVA 11990 ``Dynamic'' Inversion

时间:2015-10-08 16:21:53      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:

题目要求可转化为查询一个区间内有多少数比val大(或者小)。

区间用线段树分解(logN),每个区间维护一rank树。

rank可用BIT查询,但是为了保证不同区间的BIT互不影响要先离散。

首先进行分治,分治的同时归并排序完成离散并计算保存出每个元素和其他元素构成的逆序对iv[i]。

初始值将所有iv求和,一个对被算了两次所以除以二。

每次删除元素val就减去val对应的逆序对。

减去iv[val],但是多减去了和之前删掉元素构成的逆序对(这些逆序对已经算过一次)。

所以把删掉的元素加到线段树里面。

减去当前iv[val]之后,查询并加上当前元素val和之前位置以及之后位置构成逆序对。

复杂度

O(nlogn)预处理,O(m*logn*logn)回答

#include<bits/stdc++.h>
using namespace std;


const int maxn = 2e5+5, LogN = 20;

typedef long long ll;
ll invPair;
int a[maxn],p[maxn];
int iv[maxn];
int n;

int s[maxn<<2];
int C[LogN][maxn];
int Set[LogN][maxn];

#define para int o = 1, int l = 1,int r = n,int dep = 0
#define lo (o<<1)
#define ro (o<<1|1)
#define TEMP int mid = (l+r)>>1, lc = lo, rc = ro;
#define lsn lc, l, mid, dep+1
#define rsn rc, mid+1, r, dep+1

#define lb(x) ((x)&-(x))
int sum(int C[],int x)
{
    int re = 0;
    while(x>0){
        re += C[x];
        x -= lb(x);
    }
    return re;
}

void add(int C[],int x,int d,int r)
{
    while(x<=r){
        C[x] += d;
        x += lb(x);
    }
}

int qpos;
int ql,qr,val;
void queryPrefix(para)
{
    if(1<=l&&r<=qr){
        int pos = upper_bound(Set[dep]+l,Set[dep]+r+1,val)-Set[dep]-l;//等于等于val的最大元素的编号
        invPair += s[o] - sum(C[dep]+l-1,pos);//得到大于val的元素个数
    }else {
        TEMP
        queryPrefix(lsn);
        if(qr>mid) queryPrefix(rsn);
    }
}

void querySuffix(para)
{
    if(ql<=l&&r<=n){
        int pos = lower_bound(Set[dep]+l,Set[dep]+r+1,val)-Set[dep]-l;//严格小于val的元素的编号
        invPair += sum(C[dep]+l-1,pos);
    }else {
        TEMP
        if(ql<=mid) querySuffix(lsn);
        querySuffix(rsn);
    }
}


void modify(para)
{
    s[o]++;
    if(l == r){
        C[dep][l] = 1;
    }else{
        TEMP
        if(qpos<=mid) modify(lsn);
        else modify(rsn);
        int pos = upper_bound(Set[dep]+l,Set[dep]+r+1,val)-Set[dep]-l;//val在set里,从1开始编号
        add(C[dep]+l-1,pos,1,r-l+1);//l-1是0号位,容纳r-l+1个元素
    }
}


//为保证BIT之间互不影响,merge_sort离散,同时计算逆序对
void discretize(para)
{
    s[o] = 0;
    memset(C[dep]+l,0,sizeof(int)*(r-l+1));
    if(l == r) {
        Set[dep][l] = a[l];
        return;
    }else {
        TEMP;
        discretize(lsn);
        discretize(rsn);
        int p = l, q = mid+1, k = l;
        while(p<=mid || q<=r){
            if(q > r|| (p <= mid && Set[dep+1][p] <= Set[dep+1][q]) ){
                iv[Set[dep+1][p]] += k-p;//和后面的数构成逆序对
                Set[dep][k++] = Set[dep+1][p++];
            }else {
                iv[Set[dep+1][q]] += mid-p+1;//和前面的数构成逆序对
                Set[dep][k++] = Set[dep+1][q++];
            }
        }
    }
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    int m;
    while(~scanf("%d%d",&n,&m)){
        memset(iv+1,0,sizeof(int)*n);
        for(int i = 1; i <= n; i++){
            scanf("%d",a+i);
            p[a[i]] = i;
        }
        invPair = 0;
        discretize();
        for(int i = 1; i <= n; i++){
            invPair += iv[i];
        }
        invPair >>= 1;
        while(m--){
            scanf("%d",&val);
            printf("%lld\n",invPair);
            invPair -= iv[val];
            qr = p[val]-1;
            ql = p[val]+1;
            if(qr>=1) queryPrefix();
            if(ql<=n) querySuffix();
            qpos = p[val];
            modify();
        }
    }
    return 0;
}

 

UVA 11990 ``Dynamic'' Inversion

标签:

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

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