题目:

老瞎眼有一个长度为 n 的数组 a,为了为难小鲜肉,他准备了 Q 次询问,每次给出 一个区间[L,R],他让小鲜肉寻 找一对 l,r 使L<=l<=r<=R 且 a[l] ^ a[l+1] ^ a[l+2]… ^ a[r]=0,老瞎眼只让他回答r-l+1 最小是多少,若没有符合条件的 l,r 输出”-1”。

输入描述:

第一行输入 n,Q。
第二行输入 n 个数,表示 a 数组。
接下来 Q 行,每行输入 L,R。
1<=n,Q<=500000,0<=a[i]<=1000000,1<=L<=R<=n

输出描述:

若有解,输出 r-l+1 最小是多少。
否则输出“-1”。

示例1

输入

4 2
2 1 3 3
1 2
1 3

输出

-1
3

说明

第一次询问无解。
第二次询问:
l=1,r=3

思路:

  • 我们知道a ^ a = 0,那我们也很容易就知道 a ^ 0 = a,所以如果a = b ^ c ^ d = b ^ c ^ d ^ e ^ f ^ g,那么e ^ f ^ g = 0.
  • 利用上述特点,我们将所有的前缀异或的结果记录在pre[ ]里,并且我们可以将所有输入的查询区间按照右端点升序排序。我们跑一个Q的循环,pos记录当前在1 -> n 的哪个位置,并且用一个dot[ ]数组记录前缀异或结果出现的最近的位置,如果这个前缀异或结果在前面的位置dot[ 1 ]出现过,那么就说明这两个位置中间的这段是异或为0的。
  • 建一棵线段树,初始化为INF。每当我们找到前缀异或结果出现两次(或以上)的时候就进行线段树单点更新:将区间长度记录在这个区间的左端点处。
  • Imagine this: pos是随着区间更新变化的,相当于是跑了一个n的循环,在这个时候一直更新着线段树的值,并且总是能保证更新过的线段树是当前查询区间内的可行最小值。如果遇到pos在某个查询区间没有增加,那么就说明这个区间在当前的pos前面就已经更新完了,不需要再次更新。

注意:

  • dot[ i ]:记录前缀异或结果的位置。1e6内的数异或结果最大即二进制每位都为1。而2 ^ 19 < 1e6 <2 ^ 20,所以20位1,即2 ^ 21 - 1 < 21 e 5。
  • 反正就是要注意这个数组的大小,不要开小了。

ps:结合代码手动模拟一下就懂了。【这么诡异的题怎么能是我想出来的!terrible!】

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define P(x) x < 0 ? 0 : x
#define MID  (l + r) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1 , r
#define QL Lson, ql, qr
#define QR Rson, ql, qrusing namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 5e5 + 5;
const int maxM = 3e6 + 5;int n, Q, a[maxN], pre[maxN];
int dot[maxM]; // dot[i]:记录前缀i最新出现的位置
int ans[maxN]; // ans[i]:记录第i个查询的答案struct node{int a, b, id; //id:记录第几个输入friend bool operator < (node n1, node n2) { return n1.b < n2.b ; }
}range[maxN];int tree[maxN << 2];
void pushup(int rt) { tree[rt] = min(tree[lsn], tree[rsn]); return ;}
void build_tree(int rt , int l, int r)
{tree[rt] = INF;if(l == r) return ;int mid = MID;build_tree(Lson);build_tree(Rson);
}
void update_point(int rt, int l, int r, int pos, int val)
{if(l == r) { tree[rt] = min(tree[rt], val); return ;}int mid = MID;if(pos <= mid) update_point(Lson, pos, val);else if(pos > mid) update_point(Rson, pos, val);pushup(rt);
}int Query(int rt, int l, int r, int ql, int qr)
{if(l >= ql && r <= qr) { return tree[rt]; }int mid = MID;if(qr <= mid) return Query(QL);else if(ql > mid) return Query(QR);else return min(Query(QL), Query(QR));
}int main()
{scanf("%d%d", &n, &Q);build_tree(1, 1, n);for(int i = 1 ; i <= n ; i ++ ){scanf("%d", &a[i]);pre[i] = pre[i - 1] ^ a[i];}for(int i = 1 ; i <= Q ; i ++ ){scanf("%d%d", &range[i].a, &range[i].b);range[i].id = i;}sort(range + 1, range + Q + 1); //按照区间右端点升序排序int pos = 1;//记录当前为1 -> n这个区间的哪一个位置for(int i = 1 ; i <= Q ; i ++ ){while(pos <= range[i].b){if( pre[pos] == 0 && dot[pre[pos]] == 0)update_point(1, 1, n, 1, pos);if(dot[pre[pos]])update_point(1, 1, n, dot[pre[pos]] + 1, pos - dot[pre[pos]]);dot[pre[pos]] = pos;//更新前缀的位置pos ++ ;}ans[range[i].id] = Query(1, 1, n, range[i].a, range[i].b);}for(int i = 1 ; i <= Q ; i ++ ){if(ans[i] == INF)printf("-1\n");elseprintf("%d\n", ans[i]);}return 0;
}

【线段树-单点更新 区间查询 ^ 是大哥】老瞎眼 pk 小鲜肉(牛客)相关推荐

  1. CDOJ 1073 线段树 单点更新+区间查询 水题

    H - 秋实大哥与线段树 Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%lld & %llu Submit S ...

  2. 【原创】tyvj1038 忠诚 计蒜客 管家的忠诚 线段树(单点更新,区间查询)...

    [原创]tyvj1038 忠诚 & 计蒜客 管家的忠诚 & 线段树(单点更新,区间查询) 最简单的线段树之一,中文题目,不翻译.... 注释讲的比较少,这已经是最简单的线段树,如果看不 ...

  3. HDUOJ----1166敌兵布阵(线段树单点更新)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  4. poj 2892---Tunnel Warfare(线段树单点更新、区间合并)

    题目链接 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensiv ...

  5. HDU - 1166敌兵布阵+HDU-1754 I Hate It (线段树单点更新——累加/最大值)

    线段树单点更新,模板题 HDU1166 敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和T ...

  6. 线段树(单点更新,区间查询) HDU 1754 I Hate It

    题目链接 线段树的模板 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include&l ...

  7. FZU 2297 Number theory【线段树/单点更新/思维】

    Given a integers x = 1, you have to apply Q (Q ≤ 100000) operations: Multiply, Divide. Input First l ...

  8. poj3468 线段树区间更新+区间查询

    题目链接: http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limi ...

  9. 线段树——单点更新(二)

    HDU 4217 Data Structure? http://acm.hdu.edu.cn/showproblem.php?pid=4217 CZ做的一道题目,我帮忙看了看. 题意:给定N个数(1- ...

  10. CodeforcesBeta Round #19 D. Points 离线线段树 单点更新 离散化

    题目链接: http://codeforces.com/contest/19/problem/D 题意: 有三种操作"add x y"往平面上添加(x,y)这个点,"re ...

最新文章

  1. YJango的循环神经网络——实现LSTM YJango的循环神经网络——实现LSTM YJango YJango 7 个月前 介绍 描述最常用的RNN实现方式:Long-Short Term Me
  2. CMPP3.0 长短信实现方案
  3. Python函数传参方式超级大汇总
  4. 大数据——sqoop操作mysql和hive导出导入数据
  5. CAS单点登陆,URL多出个参数jsessionid导致登陆失败问题
  6. iOS 监听锁屏/解锁事件
  7. openmeetings(开源视频会议系统)的详细安装步骤 (windows版)
  8. sqlmap安装(python2或python3都行)
  9. exescope使用
  10. P问题,NP问题,NP完全问题,NP难问题
  11. 学plc还是学java_要学PLC想走PLC工程师之路的看看
  12. 黄卫龙 谈“太极起势”的练法
  13. 抽象、封装、继承、多态--基本理解
  14. Java笔记整理六(File类,递归,字节流IO,字符流IO,流中的异常处理,属性集Properties,缓冲流,转换流,序列化,打印流)
  15. S4 MIGO屏幕增强
  16. java计算机毕业设计高校游泳馆信息管理源码+mysql数据库+系统+lw文档+部署
  17. 软件需求工程-方法总结
  18. 图解SQL SERVER 2008R2安装与配置
  19. 双系统装完只能u盘启动_双系统引导失败如何修复教程?用NTBootAutofix一键修复...
  20. python变量加点_小白学 Python(4):变量基础操作

热门文章

  1. 计算机科学 贺楠,计算机学部-黑龙江东方学院.DOC
  2. 知行:程序员如何保持二者的平衡
  3. Crypto_[QCTF2018]Xman-RSA
  4. J.A.R.V.I.S.
  5. 解决Firefox3下Flashgot的”AddRef”问题
  6. 阿里云服务器租用测试
  7. CSS3简明教程-1.1.CSS3是什么
  8. java 证书错误_java – SSL证书错误:certificate_unknown
  9. openpyxl 打开大文件很慢_解决python执行较大excel文件openpyxl慢问题
  10. java对象 内存逃逸_JVM内存逃逸