• 【cdq分治】【CF1093E】 Intersection of Permutations


    传送门

    果然前两天写完咕咕咕那个题的题解以后博客就开始咕咕咕了……

    Description

    给定整数 (n) 和两个 (1~sim~n) 的排列 (A,B)

    (m) 个操作,操作有两种:

    • (1~,~l1~,~r1~,~l2~,~r2)((igcup_{i=l1}^{r1} A_i)~igcap~(igcup_{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~ imes~10^5)

    Solution

    这不是hash+二维树状数组好题嘛!

    然而因为一次操作有 (4) 次查询,相当于操作次数 (10^6),hash树状数组显然过不去= =

    考虑如果给 (B) 重编号,(B_i) 代表原 (B) 中第 (i) 个元素在 (A) 中出现的位置,那么每次查询就等价于区间 ([l2, r2]) 中有多少个数在 ([l1,r1]) 内。于是这个问题被转化成了一个二维数点问题那我们去写hash+树状数组吧!,并且资瓷离线,于是考虑cdq分治过掉

    这里记录一下待修改的cdq怎么写:将一次修改操作改为一个添加操作和一个删除操作。例如,交换 (x, y) 等价于删除 ((x,B_x),(y,B_y)),并且加入 ((x,B_y),(y,B_x))。初始的序列以添加的形式给出

    于是复杂度 (O(nlog^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
    ", 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
    ", 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], '
    ', 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处理带修问题时,将修改变为删除和插入。

  • 相关阅读:
    《JavaScript高级程序设计》读书笔记 ---Object 类型
    《JavaScript高级程序设计》读书笔记 ---变量、作用域和内存问题小结
    《JavaScript高级程序设计》读书笔记 ---执行环境及作用域
    《JavaScript高级程序设计》读书笔记 ---基本类型和引用类型的值
    《JavaScript高级程序设计》读书笔记 ---函数
    《JavaScript高级程序设计》读书笔记 ---基本概念小结
    《JavaScript高级程序设计》读书笔记 ---语句
    《JavaScript高级程序设计》读书笔记 ---if语句
    Vue2.0组件间数据传递
    UIButton快速点击,只执行最后一次
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10158773.html
Copyright © 2020-2023  润新知