zoukankan      html  css  js  c++  java
  • 【题解】简单题 By 5ab as a juruo

    题目

    题目来源:CCF CQOI2006;

    评测地址:Luogu#5057

    题目描述

    有一个 (n) 个元素的数组,每个元素初始均为 (0)

    (m) 条指令,要么让其中一段连续序列数字反转——(0)(1)(1)(0)(操作 1),要么询问某个元素的值(操作 2)。

    例如当 n = 20 时,10 条指令如下:

    辣鸡洛谷图床,又炸了

    输入格式

    第一行包含两个整数 (n)(m),表示数组的长度和指令的条数;

    以下 (m) 行,每行的第一个数 (t) 表示操作的种类:

    • (t=1),则接下来有两个数 (L)(R),表示区间 ([L, R]) 的每个数均反转;
    • (t=2),则接下来只有一个数 (i),表示询问的下标。

    输出格式

    每个操作 2 输出一行(非 (0)(1)),表示每次操作 2 的回答。

    数据规模及约定

    评测时间限制 (1000 extrm{ms}),空间限制 (512 extrm{MiB})

    • 对于 (50\%) 的数据,(1le nle 10^3)(1le mle 10^4)
    • 对于 (100\%) 的数据,(1le nle 10^5)(1le mle 5 imes 10^5)

    保证 (1le Lle Rle n)

    分析

    题意很清楚。将一个 (0/1) 数列区间求反,单点查询,是一道不折不扣的数据结构题。

    看到区间修改,首先想到的就是线段树。但是 (mle 5 imes 10^5),线段树常数又大,很容易超时。所以,我们考虑树状数组。

    注意到区间求反就是区间异或运算,所以可以用树状数组维护。再用区间查询差分来单点查询。实际测试 在不吸氧的情况下跑到将近 (100) ms。

    Code

    注意区分树状数组的单点/区间和实际操作的单点/区间,因为树状数组存储的实际上是差分操作后的原数列。

    #include <cstdio>
    #include <cctype>
    using namespace std;
    
    const int max_n = 100000;
    bool tr[max_n+1] = {};
    int n;
    
    inline int lowbit(int x) { return x & -x; }
    
    inline int read() // 10^6 的输入,加上快读比较保险
    {
    	int ch = getchar(), t = 1, n = 0;
    	while (isspace(ch)) { ch = getchar(); }
    	if (ch == '-') { t = -1, ch = getchar(); }
    	while (isdigit(ch)) { n = n * 10 + ch - '0', ch = getchar(); }
    	return n * t;
    }
    
    void add(int p) // 树状数组单点修改
    {
    	while (p <= n)
    	{
    		tr[p] ^= true;
    		p += lowbit(p);
    	}
    }
    
    bool get(int p) // 树状数组的区间查询
    {
    	bool res = false;
    
    	while (p > 0)
    	{
    		res ^= tr[p];
    		p -= lowbit(p);
    	}
    
    	return res;
    }
    
    void modify(int l, int r) // 原数组的区间修改 <- 差分数组的单点修改
    {
    	add(l);
    	
    	if (r != n)
    		add(r+1);
    }
    
    int main()
    {
    	int m, opt, ta, tb;
    
    	n = read(), m = read(); // 输入
    	for (int i = 0; i < m; i++)
    	{
    		opt = read(); // 编号
    
    		if (opt == 1) // 修改操作
    		{
    			ta = read(), tb = read();
    			modify(ta, tb);
    		}
    		else // 查询操作
    		{
    			ta = read();
    			printf("%d
    ", get(ta)); // 原数组的单点查询 <- 差分数组的前缀和(误,应该是 xor)
    		}
    	}
    
    	return 0;
    }
    

    后记

    这道题比较卡常,如果线段树常数比较大的话可能就过不了。

    做数据结构题时,最好用最适合的数据结构,而非功能最强大的。否则用暴力不香吗

  • 相关阅读:
    js-快速选择日期区间
    关于状态更新时间字段取值的问题
    MySql 前缀索引
    Java springMVC 多数据源的实现和使用
    哈哈哈,终于找到一个安稳的“家”了
    POJ 1724: Roads
    POJ 1221: UNIMODAL PALINDROMIC DECOMPOSITIONS
    createjs 用户画线 粗细bug Graphics setStrokeStyle() 粗细BUG
    GAudio是一个音频播放SDK
    新做的一个基于OPENGL的gui库
  • 原文地址:https://www.cnblogs.com/5ab-juruo/p/solution-cqoi2006_lg5057.html
Copyright © 2011-2022 走看看