1. 程式人生 > 其它 >CF785E (動態逆序對)

CF785E (動態逆序對)

題意描述

對長度為\(n\)的排列進行\(k\)次操作,每次操作交換兩個數字,求每次交換以後,整個序列的逆序對數量

思路

\(1.\) 分塊
對於查詢和修改,我們可以直接在塊內暴力解決。
觀察發現,如果交換\(a[l]\)\(a[r]\),則對\([l + 1, r - 1]\)區間內有影響的數的值域在\([a[l],a[r]]\)之間。
因為上面的性質,對於整塊我們要快速找到值域在\([a[l],a[r]]\)的數,所以對於每個塊我們可以維護一個有序的vector,這樣查詢操作就可以快速解決。
對於修改來說,我們直接在對應的塊內暴力修改,修改完後一定要對vector排序
對於查詢來說,非整塊可以直接暴力找值域在\([a[l],a[r]]\)

範圍內的數,整塊的話,可以二分找到\(a[l]\)\(a[r]\),再相減即可(可以用\(lower\_bound\)\(upper\_bound\),由於是閉區間,所以對於右端點必須使用\(upper\_bound\),但是本題中是排列,所以無影響),記\([a[l],a[r]]\)的數量為\(cnt\),則總貢獻為\((2*cnt)+1\),如果\(a[l] > a[r]\)則此時的交換操作會導致逆序對減少,特判即可。
總複雜度為\(O(q\sqrt{n}logn)\)
\(2.\) 樹套樹

待補

程式碼

#include <bits/stdc++.h>

#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()

using ll = long long;
using pii = std::pair<int, int>;

const int MOD = 1e9 + 7;
const int N = 2 * 1e5 + 5;
const int INF = 0x3f3f3f3f;

int a[N], n, k, block;
std::vector<int> g[N];

void init()
{
    block = sqrt(n + 0.5);
    for(int i = 1; i <= n; ++i)
    {
        a[i] = i;
        g[i / block].push_back(a[i]);
    }
}

ll query(int l, int r)
{
    int idl = l / block, idr = r / block;
    int x = a[l], y = a[r];
    int k = std::lower_bound(g[idl].begin(), g[idl].end(), x) - g[idl].begin();
    g[idl][k] = y;
    std::sort(g[idl].begin(), g[idl].end());
    k = std::lower_bound(g[idr].begin(), g[idr].end(), y) - g[idr].begin();
    g[idr][k] = x;
    std::sort(g[idr].begin(), g[idr].end());
    ll ans = 0, f;
    // 特判符號位
    if(x > y) f = -1, std::swap(x, y);
    else f = 1;

    if(idl == idr)
    {
        for(int i = l; i <= r; ++i)
        {
            if(x < a[i] && a[i] < y) ++ans;
        }
    }
    else
    {
        int i = l, j = r;
        while(i / block == l / block)
        {
            if(x < a[i] && a[i] < y)
            {
                ++ans;
            }
            ++i;
        }
        while(j / block == r / block)
        {
            if(x < a[j] && a[j] < y)
            {
                ++ans;
            }
            --j;
        }
        for(int k = i / block; k <= j / block; ++k)
        {
            ans += std::upper_bound(g[k].begin(), g[k].end(), y) - std::lower_bound(g[k].begin(), g[k].end(), x);
        }
    }
    std::swap(a[l], a[r]);
    return f * (2 * ans + 1);
}

void solve()
{
    std::cin >> n >> k;
    init();
    ll ans = 0;
    while(k--)
    {
        int l, r;
        std::cin >> l >> r;
        if(l > r) std::swap(l, r);
        if(l != r) ans += query(l, r);
        std::cout << ans << '\n';
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cout << std::fixed << std::setprecision(8);
    int T = 1;
    // std::cin >> T;
    while(T--) solve();
}