CF1093E Intersection of Permutations 樹狀陣列套權值線段樹
阿新 • • 發佈:2019-01-06
\(\color{#0066ff}{ 題目描述 }\)
給定整數 \(n\) 和兩個 \(1,\dots,n\) 的排列 \(a,b\)。
\(m\) 個操作,操作有兩種:
- \(1\ l_a\ r_a\ l_b\ r_b\),設 \(a\) 的 \([l_a;r_a]\) 區間內的元素集合為 \(S_a\),設 \(b\) 的 \([l_b;r_b]\) 區間內的元素集合為 \(S_b\),求 \(\lvert S_a \bigcap S_b \rvert\)。
- \(2\ x\ y\),交換 \(b\) 的第 \(x\) 位與第 \(y\) 位。
\(1 \le n,m \le 2 \cdot 10^5\)
\(\color{#0066ff}{輸入格式}\)
第一行,兩個整數 \(n,m\) 以下兩行,每行 \(n\) 個整數,分別表示 \(a,b\)。 以下 \(m\) 行,每行一個操作。
\(\color{#0066ff}{輸出格式}\)
對於每個 \(1\) 操作,輸出答案。
\(\color{#0066ff}{輸入樣例}\)
6 7
5 1 4 2 3 6
2 5 3 1 4 6
1 1 2 4 5
2 2 4
1 1 2 4 5
1 2 3 3 5
1 1 6 1 2
2 4 1
1 4 4 1 3
\(\color{#0066ff}{輸出樣例}\)
1
1
1
2
0
\(\color{#0066ff}{資料範圍與提示}\)
\(2\leq n \leq 2*10^5, 1\leq m \leq 2*10^5\)
\(\color{#0066ff}{ 題解 }\)
對於排列的每個元素,都有在a中出現的位置pa,在b中出現的位置pb
將其當做二維點(pa,pb),那麼其實這題就建好模了
給你二維平面上的一些點
有交換兩個點的y座標操作
每次查詢一個矩形內有多少點
樹套樹
樹狀陣列套權值線段樹
樹狀陣列維護pb, 權值線段樹維護對應區間的pa
在權值線段樹上找到對應區間返回
要寫陣列版,而且還得記憶體回收,作為指標選手,以哭暈qwq
#include<bits/stdc++.h> #define LL long long LL in() { char ch; int x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f; } const int maxn = 1e6 * 40; const int N = 2e5 + 10; struct node { int num; int ch[2]; int &operator [] (const int &b) { return ch[b]; } node(int a = 0): num(a) { ch[0] = ch[1] = 0; } }e[maxn]; int a[N], b[N], pa[N], pd[N], cnt; int root[N]; int n, m; int sta[N], top; int low(int x) { return (x) & (-x); } int newnode() { return top? sta[top--] : ++cnt; } void add(int &now, int pos, int k, int l, int r) { if(!now) now = newnode(); e[now].num += k; if(l == r) return; int mid = (l + r) >> 1; if(pos <= mid) add(e[now][0], pos, k, l, mid); else add(e[now][1], pos, k, mid + 1, r); if(!e[now].num) sta[++top] = now, now = 0; } void add(int pos, int val, int k) { for(int i = pos; i <= n; i += low(i)) add(root[i], val, k, 1, n); } int query(int L, int R, int now, int l, int r) { if(!now) return 0; if(L <= l && r <= R) return e[now].num; int mid = (l + r) >> 1, tot = 0; if(L <= mid) tot += query(L, R, e[now][0], l, mid); if(R > mid) tot += query(L, R, e[now][1], mid + 1, r); return tot; } int query(int L, int R, int l, int r) { int ans = 0; for(int i = L - 1; i; i -= low(i)) ans -= query(l, r, root[i], 1, n); for(int i = R; i; i -= low(i)) ans += query(l, r, root[i], 1, n); return ans; } int main() { n = in(), m = in(); for(int i = 1; i <= n; i++) a[i] = in(), pa[a[i]] = i; for(int i = 1; i <= n; i++) b[i] = pa[in()]; for(int i = 1; i <= n; i++) add(i, b[i], 1); int flag, l, r, L, R; while(m --> 0) { flag = in(); if(flag == 1) { L = in(), R = in(), l = in(), r = in(); printf("%d\n", query(l, r, L, R)); } else { l = in(), r = in(); add(l, b[l], -1); add(r, b[r], -1); add(l, b[r], 1); add(r, b[l], 1); std::swap(b[l], b[r]); } } return 0; }