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; }