CodeForces 785E Anton and Permutation 分块

题意:

有一个\(1 \sim n\)的排列\(A\),有\(q\)个询问:
交换任意两个元素的位置,求交换之后排列的逆序数

分析:

像这种不太容易用线段树,树状数组维护的可以考虑分块
\(\sqrt{n}\)个元素划分为一块,然后两端的块可以直接扫出逆序数的变化,中间的块可以用二分计算逆序数
在更新块的时候,可以二分查找要插入或删除的位置
每次询问的复杂度为\(O(\sqrt{n}log\sqrt{n})=O(\sqrt{n}logn)\)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;

const int maxn = 200000 + 10;
const int maxsqrt = 500;

#define ALL(x) x.begin(), x.end()

int n, q, a[maxn];
int st[maxsqrt], ed[maxsqrt];
vector<int> b[maxsqrt];

int main()
{
    scanf("%d%d", &n, &q);
    int col = (int)sqrt(n);
    for(int i = 0; i < n / col; i++) { st[i] = col * i; ed[i] = col * (i + 1); }
    if(n % col > 0) { st[n / col] = n - (n % col); ed[n / col] = n; }

    for(int i = 0; i < n; i++) {
        a[i] = i;
        b[i / col].push_back(i);
    }

    long long ans = 0;
    while(q--) {
        int l, r; scanf("%d%d", &l, &r);
        l--; r--;
        if(l == r) { printf("%lld\n", ans); continue; }
        if(l > r) swap(l, r);
        int idl = l / col, idr = r / col;

        //update
        for(int i = idl + 1; i < idr; i++) {
            int size = b[i].size();
            int p = lower_bound(ALL(b[i]), a[l]) - b[i].begin();
            ans -= p;
            ans += size - p;
            p = lower_bound(ALL(b[i]), a[r]) - b[i].begin();
            ans += p;
            ans -= size - p;
        }

        for(int i = l + 1; i < ed[idl] && i < r; i++) {
            if(a[i] > a[l]) ans++; else ans--;
            if(a[i] > a[r]) ans--; else ans++;
        }
        for(int i = st[idr]; i < r && i > l; i++) {
            if(a[i] > a[l]) ans++; else ans--;
            if(a[i] > a[r]) ans--; else ans++;
        }
        
        //swap
        if(idl < idr) {
            b[idl].erase(lower_bound(ALL(b[idl]), a[l]));
            b[idl].insert(lower_bound(ALL(b[idl]), a[r]), a[r]);
            b[idr].erase(lower_bound(ALL(b[idr]), a[r]));
            b[idr].insert(lower_bound(ALL(b[idr]), a[l]), a[l]);
        }
        if(a[l] < a[r]) ans++; else ans--;
        swap(a[l], a[r]);

        printf("%lld\n", ans);
    }

    return 0;
}
posted @ 2017-03-18 16:09 AOQNRMGYXLMV 阅读(...) 评论(...) 编辑 收藏