Educational Codeforces Round 56 (Rated for Div. 2) E. Intersection of Permutations(分塊 + 樹狀數組)

題目鏈接:https://codeforces.com/contest/1093/problem/E

題目大意:給出兩個1~n的排列 a 和 b;對這兩個排列進行如下兩種操作:

1 la ra lb rb:查詢排列 a 的區間 [la,ra] 與排列 b 的區間 [lb,rb]內有多少個相同的數;

 

2 x y:將b[x] 與 b[y]的值進行交換。

題目思路:·由於更新操作中只會對排列 b 進行修改,所以我們可以用一個pos數組來記錄排列 a 中各個數的位置。

這樣我們就可以知道排列 b 中的各個數在 a 中所對應的位置是哪裏。

這樣我們就可以用一個二維樹狀數組 bit[i][j] 來維護,bit[i][j] 表示在b[1] ~ b[i] 中與 a[1]~a[j]中有多少個相同的數。

一開始的時候可以就是對於每一個 b[i] 將 bit[i][pos[b[i]] ~ bit[n][n]加1,代表在這個區間內是有一個相同的數。

查詢的時候就是 sum(ra,rb) - sum(la-1,rb) - sum(ra,lb-1) + sum(la-1,lb-1)。(sum(x,y) 就是一個正常的二維樹狀數組查詢)

但現在由於n 最大可以達到 2e5,無法直接開一個bit[2e5][2e5]的數組,所以我們就考慮分塊。

將b排列 分爲sqrt(n)個部分,前面的更新是一個點一個點的更新,現在更新是一個部分一個部分的更新,更新一個點的時候也就是更新相應的塊的內容。

這樣就可以將數組的大小縮減爲:bit[sqrt(2e5)][2e5],這就是一個可接受的範圍了。

在查詢的時候,就查詢其所在塊的情況就可以了,但還有一點要注意的就是,查詢區間右端點所在塊的信息的時候,要將這一塊單獨取出來查詢計算(因爲並不是將這一整塊的信息查詢,只需要到右端點部分的信息)。

分塊之後的時間複雜度就大概是O(m*log(sqrt(n))*log(n))。6s的時間就綽綽有餘了。

具體實現看代碼:

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define MP make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(a) memset(a,0,sizeof(a))
#define _inf(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<#x<<" " << (x) << "]"<<endl
using namespace std;
typedef long long ll;
typedef pair<int, int>pii;
const int MX = 2e5 + 5;
const int inf = 0x3f3f3f3f;

int n, m;
int bsz, nsz, pos[MX], b[MX];
int block[MX];
int bit[500][MX];
inline int lowbit(int x) {return x & -x;}

inline void upd(int x, int y, int d) {
    int tmp = block[y] + 1;
    for (int i = tmp; i <= nsz; i += lowbit(i)) {
        for (int j = x; j <= n; j += lowbit(j))
            bit[i][j] += d;
    }
}
inline int ask(int x, int y) {
    int res = 0;
    int tmp = block[y];
    for (int i = max(tmp * bsz, 1); i <= y; i++) if (b[i] <= x) res++;
    for (int i = tmp; i; i -= lowbit(i)) {
        for (int j = x; j; j -= lowbit(j))
            res += bit[i][j];
    }
    return res;
}

int main() {
    // FIN;
    scanf("%d%d", &n, &m);
    bsz = (int)sqrt(n);
    nsz = n / bsz;
    for (int i = 1; i <= n; i++) {
        int x; scanf("%d", &x);
        pos[x] = i;
        block[i] = i / bsz;
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &b[i]);
        b[i] = pos[b[i]];
        upd(b[i], i, 1);
    }
    int op, la, ra, lb, rb;
    while (m--) {
        scanf("%d", &op);
        if (op == 1) {
            scanf("%d%d%d%d", &la, &ra, &lb, &rb);
            int ans = ask(ra, rb) - ask(la - 1, rb) - ask(ra, lb - 1) + ask(la - 1, lb - 1);
            printf("%d\n", ans);
        } else {
            scanf("%d%d", &lb, &rb);
            upd(b[lb], lb, -1); upd(b[rb], rb, -1);
            swap(b[lb], b[rb]);
            upd(b[lb], lb, 1); upd(b[rb], rb, 1);
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章