【cdq分治】【CF1093E】 Intersection of Permutations
阿新 • • 發佈:2018-12-21
復雜度 pda 刪除 記錄 code ask pan span 輸出
等價於刪除 \((x,B_x),(y,B_y)\),並且加入 \((x,B_y),(y,B_x)\)。初始的序列以添加的形式給出
傳送門
果然前兩天寫完咕咕咕
那個題的題解以後博客就開始咕咕咕了……
Description
給定整數 \(n\) 和兩個 \(1~\sim~n\) 的排列 \(A,B\)。
\(m\) 個操作,操作有兩種:
- \(1~,~l1~,~r1~,~l2~,~r2\) 求\((\bigcup_{i=l1}^{r1} A_i)~\bigcap~(\bigcup_{i=l2}^{r2} B_i)\)
- \(2~,~x~,~y\) 交換 \(B_x,~B_y\)
Input
第一行是兩個正整數 \(n,m\)
下面兩行,每行 \(n\) 個數, 給出排列 \(A,B\)
下面 \(m\) 行,每行一個操作
Output
對每個詢問輸出一行代表答案
Hint
\(0~\leq~n,m~\leq~2~\times~10^5\)
Solution
這不是hash+二維樹狀數組好題嘛!
然而因為一次操作有 \(4\) 次查詢,相當於操作次數 \(10^6\),hash樹狀數組顯然過不去= =
考慮如果給 \(B\) 重編號,\(B_i\) 代表原 \(B\) 中第 \(i\) 個元素在 \(A\) 中出現的位置,那麽每次查詢就等價於區間 \([l2, r2]\) 中有多少個數在 \([l1,r1]\) 內。於是這個問題被轉化成了一個二維數點問題那我們去寫hash+樹狀數組吧!,並且資瓷離線,於是考慮cdq分治過掉
這裏記錄一下待修改的cdq怎麽寫:將一次修改操作改為一個添加操作和一個刪除操作。例如,交換 \(x, y\)
於是復雜度 \(O(n\log^2n)\),可以過掉本題
Code
#include <cstdio> #include <algorithm> #ifdef ONLINE_JUDGE #define freopen(a, b, c) #endif #define rg register #define ci const int #define cl const long long typedef long long int ll; namespace IPT { const int L = 1000000; char buf[L], *front=buf, *end=buf; char GetChar() { if (front == end) { end = buf + fread(front = buf, 1, L, stdin); if (front == end) return -1; } return *(front++); } } template <typename T> inline void qr(T &x) { rg char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar(); if (lst == '-') x = -x; } template <typename T> inline void ReadDb(T &x) { rg char ch = IPT::GetChar(), lst = ' '; while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar(); while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar(); if (ch == '.') { ch = IPT::GetChar(); double base = 1; while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar(); } if (lst == '-') x = -x; } namespace OPT { char buf[120]; } template <typename T> inline void qw(T x, const char aft, const bool pt) { if (x < 0) {x = -x, putchar('-');} rg int top=0; do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10); while (top) putchar(OPT::buf[top--]); if (pt) putchar(aft); } const int maxn = 200010; const int maxt = 1000010; struct Zay { int id, x, y, mul, oppt, vec; inline void setit(ci _a, ci _b, ci _c, ci _d, ci _e, ci _f) { id = _a; x = _b; y = _c; mul = _d; oppt = _e; vec = _f; } }; Zay opt[maxt], temp[maxt]; inline int lowbit(ci &x) {return x & -x;} int n, m, cnt, tot; int CU[maxn], MU[maxn], ans[maxn], tree[maxt]; int ask(int); void cdq(ci, ci); void add(int, ci); void query(const Zay&); void update(const Zay&); int main() { freopen("1.in", "r", stdin); qr(n); qr(m); int a, l1, r1, l2, r2; for (rg int i = 1; i <= n; ++i) { a = 0; qr(a); CU[a] = i; } for (rg int i = 1; i <= n; ++i) { a = 0; qr(a);// printf("QWQ%d\n", a); ++cnt; opt[cnt] = (Zay){opt[cnt - 1].id + 1, i, MU[i] = CU[a], 1, 0, 0}; } while (m--) { a = 0; qr(a);//printf("EM%d\n", a); if (a == 1) { l1 = r1 = l2 = r2 = 0; qr(l1); qr(r1); qr(l2); qr(r2); --l1; --l2; int _pre = opt[cnt].id + 1; opt[++cnt].setit(_pre, r2, r1, 1, 1, ++tot); opt[++cnt].setit(_pre, l2, r1, -1, 1, tot); opt[++cnt].setit(_pre, l2, l1, 1, 1, tot); opt[++cnt].setit(_pre, r2, l1, -1, 1, tot); } else { l1 = r1 = 0; qr(l1); qr(r1); int _pre = opt[cnt].id + 1; opt[++cnt].setit(_pre, l1, MU[l1], -1, 0, 0); opt[++cnt].setit(_pre, r1, MU[r1], -1, 0, 0); std::swap(MU[l1], MU[r1]); opt[++cnt].setit(_pre, l1, MU[l1], 1, 0, 0); opt[++cnt].setit(_pre, r1, MU[r1], 1, 0, 0); } } cdq(1, cnt); for (rg int i = 1; i <= tot; ++i) qw(ans[i], '\n', true); return 0; } void cdq(ci l, ci r) { if (l == r) return; int mid = (l + r) >> 1; cdq(l, mid); cdq(mid + 1, r); for (rg int i = l, ll = l, rr = mid + 1; i <= r; ++i) { if (ll > mid) { query(opt[rr]); temp[i] = opt[rr++]; } else if (rr > r) { update(opt[ll]); temp[i] = opt[ll++]; } else if (opt[ll].x <= opt[rr].x) { update(opt[ll]); temp[i] = opt[ll++]; } else { query(opt[rr]); temp[i] = opt[rr++]; } } for (rg int i = l; i <= mid; ++i) if (!opt[i].oppt) { add(opt[i].y, -opt[i].mul); } for (rg int i = l; i <= r; ++i) opt[i] = temp[i]; } inline void update(const Zay &_t) { if (_t.oppt) return; add(_t.y, _t.mul); } inline void query(const Zay &_t) { if (!_t.oppt) return; ans[_t.vec] += _t.mul * ask(_t.y); } void add(int x, ci v) { while (x <= n) { tree[x] += v; x += lowbit(x); } } int ask(int x) { int _ret = 0; while (x) { _ret += tree[x]; x -= lowbit(x); } return _ret; }
Summary
cdq處理帶修問題時,將修改變為刪除和插入。
【cdq分治】【CF1093E】 Intersection of Permutations