Gym 100342F Move to Front (树状数组动态维护和查询)

用树状数组动态和查询修改排名。

树状数组可以很方便地查询前缀和,那么可以利用这一特点,记录一个点在树状数组里最后一次出现的位置,

查询出这个位置,就可以知道这个点的排名了。更改这个点的排名的时候只要把原来位置修改成0,然后在新的位置加上1就行了。

把询问离线,数据范围比较大,先用快排+去重离散(用map也可,就是慢了一点),

 

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

const int maxn = 1e5+5, N = maxn*2-1;

int a[maxn],q[maxn],C[N+1],sz,pos[maxn];

#define lowbit(x) ((x)&-(x))

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

int sum(int x)
{
    int ret = 0;
    while(x>0){
        ret += C[x]; x -= lowbit(x);
    }
    return ret;
}

int b_search(int val,int *A = a,int l = 0,int r = sz)
{
    int m;
    while(l<r){
        m = (l+r)>>1;
        if(val>A[m]) l = m+1;
        else if(val<A[m]) r = m;
        else return m;
    }
    return -1;
}

int main()
{
    freopen("mtf.in","r",stdin);
    freopen("mtf.out","w",stdout);
    int n; cin>>n;
    for(int i = 0; i < n; i++) scanf("%d",a+i),q[i]=a[i];
    sort(a,a+n);
    sz = unique(a,a+n)-a;
    for(int i = 0; i < sz; i++){
        add(pos[i] = maxn+i,1);
    }
    int cur = maxn-1;
    for(int i = 0; i < n; i++){
        int x = b_search(q[i]), ans;
        if(pos[x] == maxn+x) ans = sum(pos[x]) - x-1 + q[i];
        else ans = sum(pos[x]);
        printf("%d%c",ans,i==n-1?'
':' ');
        add(pos[x],-1);
        add(pos[x] = cur--,1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/jerryRey/p/4771114.html