zoukankan      html  css  js  c++  java
  • NAOJ33 bst

    题目蓝链

    Solution

    这道题我一开始打挂了,因为我没有考虑反转会对修改也产生影响。我们可以考虑建立一颗线段树来维护,对于每一个点开一个标记,标记的每一个二进制为表示在当前子树的第几层会全部翻转。我们只需要在修改和查询的时候把这个标记(push\_down)一下就可以了

    另外注意在修改操作的时候,因为行与行之间会产生冲突,所以只能一行一行的修改。但中间的行都是完整的,所以度杂度是(mathcal{O}(1))。只有两端的位置也就是两行需要在线段上去修改,复杂度为(mathcal{O}(log n))

    另外注意,在修改和查询的时候。在每一个点都要看一下在当前层有没有需要反转的标记,有就更改一下方向

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define squ(x) ((LL)(x) * (x))
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    
    typedef long long LL;
    typedef pair<int, int> pii;
    
    inline int read() {
    	int sum = 0, fg = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    	return fg * sum;
    }
    
    const int maxn = 1e6 + 10;
    
    int N, n, q, Pow[21];
    
    namespace ST {
    
    	int A[maxn << 4], tag[maxn << 4];
    #define ls (rt << 1)
    #define rs (rt << 1 | 1)
    
    	void push_down(int rt) {
    		if (!tag[rt]) return;
    		tag[ls] ^= tag[rt], tag[rs] ^= tag[rt];
    		A[ls] ^= tag[rt], A[rs] ^= tag[rt];
    		tag[rt] = 0;
    	}
    
    	void change(int rt, int l, int r, int L, int R, int dep, int p) {
    		if (L <= l && r <= R) { A[rt] ^= Pow[p], tag[rt] ^= Pow[p]; return; }
    		push_down(rt);
    		int mid = (l + r) >> 1, tt = (A[rt] & Pow[dep]) ? 1 : 0;
    		if (L <= mid) change(ls ^ tt, l, mid, L, R, dep + 1, p);
    		if (R > mid) change(rs ^ tt, mid + 1, r, L, R, dep + 1, p);
    	}
    
    	int query(int rt, int l, int r, int x, int dep) {
    		if (l == r) return rt - (Pow[n] - 1);
    		push_down(rt);
    		int mid = (l + r) >> 1, tt = (A[rt] & Pow[dep]) ? 1 : 0;
    		if (x <= mid) return query(ls ^ tt, l, mid, x, dep + 1);
    		else return query(rs ^ tt, mid + 1, r, x, dep + 1);
    	}
    
    }
    
    int main() {
    #ifdef xunzhen
    	freopen("33.in", "r", stdin);
    	freopen("33.out", "w", stdout);
    #endif
    
    	n = read(); q = read(); N = 1 << n;
    	Pow[0] = 1; for (int i = 1; i <= 20; i++) Pow[i] = Pow[i - 1] << 1;
    	while (q--) {
    		int op = read();
    		if (op == 1) {
    			int l = read(), r = read();
    			for (int i = 0; i < n; i++)
    				if (l < Pow[i + 1] && r >= Pow[i]) {
    					int x = max(l, Pow[i]), y = min(r, Pow[i + 1] - 1);
    					if (x == Pow[i] && y == (Pow[i + 1] - 1)) ST::A[1] ^= Pow[i], ST::tag[1] ^= Pow[i];
    					else ST::change(1, 1, Pow[i], x - (Pow[i] - 1), y - (Pow[i] - 1), 0, i);
    				}
    		}else {
    			int x = read();
    			printf("%d
    ", ST::query(1, 1, N, x, 0));
    		}
    	}
    
    	return 0;
    }
    

    Summary

    这道题要做出来,需要非常灵活地使用线段树

    做之前要仔细考虑翻转会产生的影响

  • 相关阅读:
    composer require 指定版本
    后台管理,有无限可能
    str_replace 批量查找替换字符串
    node项目配置成nginx启动
    nodejs项目安装ant design
    in_array的三个参数
    Tp5.1使用导出Excel
    php 中 public private protected的区别
    Seafile 文件访问日志时间不一致问题
    du -sh *
  • 原文地址:https://www.cnblogs.com/xunzhen/p/9723659.html
Copyright © 2011-2022 走看看