牛客练习赛53 E-老瞎眼pk小鲜肉(思维+线段树+离线)
前言
听说是线段树离线查询??
做题做着做着慢慢对离线操作有点感觉了,不过也还没参透,等再做些题目再来讨论离线、在线操作。
这题赛后看代码发现有人用的树状数组,$tql$。当然能用树状数组写的线段树也能写,最重要的还是思维上面。
我当时是怎么想来着。一看异或和前缀和不是很像么,我先把数组中所有数字连续异或并存起来,就像处理前缀和一样的。之后对于每组查询,我只要找到区间中相等的数就可以了,然后再取这些数中相隔最近的距离输出即可。想法很好,但是现实很骨感,这样一来每个区间都这样处理不就超时了么,遂放弃。
题意
给出一段长度为$n$的区间,$q$次询问求$L\sim R$这个区间内最短的一段区间$l\sim r$使得$\oplus_{i=l}^{r} a_j= 0$其中$L\leq l<r\leq r$
分析
首先预处理出对于每个位置$i$找到左边离$i$最近的位置$j$使得$a[j] \wedge a[j+1] \wedge a[j+2]\wedge …a[i]=0$,并记作$pre[i]$。
将询问按$r$从小到大排序,然后从$1\sim n$处理每个位置,对于位置$i$,在线段树上$pre[i]$更新为$i-pre[i]+1$($i$与离$i$右边最近满足$\oplus_{i=l}^{r} a_j= 0$的$r$间的距离),然后查询$(Q[i].l, Q[i].r)$的最小值即可 $[link]$
Code
#include <cstdio>
#include <algorithm>
#define lson rt<<1, l , mid
#define rson rt<<1|1, mid+1 , r
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 5e5+6;
int n, q;
int pos[maxn<<2], pre[maxn], tree[maxn<<2], ans[maxn];
struct node{
int l,r,id;
bool operator<(const node x)const{
return r<x.r;
}
}Q[maxn];
void push_up(int rt){
tree[rt] = min(tree[rt<<1], tree[rt<<1|1]);
}
void update(int rt,int l,int r,int pos,int val){
if(l==r){
tree[rt] = min(tree[rt], val);
return;
}
int mid = (l+r)>>1;
if(pos<=mid) update(lson, pos, val);
else update(rson, pos, val);
push_up(rt);
}
int query(int rt, int l, int r, int ul, int ur){
if(ul<=l&&r<=ur) return tree[rt];
int mid = (l+r)>>1, ans = INF;
if(ur<=mid) return query(lson, ul, ur);
else if(ul>mid) return query(rson, ul, ur);
else return min(query(lson, ul, ur),query(rson, ul, ur));
}
/*这种写法也可以,但是就我以前做过的一道题目来说上面那种更快(不知道为啥,还有待考证)
int query(int rt, int l, int r, int ul, int ur){
if(ul<=l&&r<=ur) return tree[rt];
int mid = (l+r)>>1, ans = INF;
if(ul<=mid) ans = min(ans, query(lson, ul, ur));
if(ur>mid) ans = min(ans, query(rson, ul, ur));
return ans;
}
*/
int main(){
scanf("%d%d", &n, &q);
for(int i = 1;i <= 4*500000; i++){
pos[i] = -1;
tree[i] = INF;
}
int sum = 0; pos[0] = 0;
for(int i = 1,x; i <= n; i++){
scanf("%d",&x);
sum ^= x;
if(pos[sum]!=-1) pre[i] = pos[sum]+1;
else pre[i] = -1;
pos[sum] = i;
}
for(int i = 1; i <= q; i++){
scanf("%d%d", &Q[i].l, &Q[i].r);
Q[i].id = i;
}
sort(Q+1, Q+1+q);
int cnt = 1;
for(int i = 1; i <= n; i++){
if(pre[i]!=-1) update(1, 1, n, pre[i], i-pre[i]+1);
while(Q[cnt].r==i){
ans[Q[cnt].id] = query(1, 1, n, Q[cnt].l, Q[cnt].r);
cnt++;
}
}
for(int i = 1; i <= q; i++){
printf("%d\n", ans[i]==INF?-1:ans[i]);
}
return 0;
}
思考
说实话现在也只是知道了这题这么做是对的,但是自己很难会想到这个方法,可能要多做些题目才知道吧,据说和HH的项链很像,有时间就去看下这题。
还有就是我看这题代码的时候有个想法就是,能不能把$update(1, 1, n, pre[i], i-pre[i]+1)$换成$update(1, 1, n, i, i-pre[i]+1)$。当时觉得这样应该是差不多的,然而$WA$。
仔细想想后,发现用$pre[i]$的位置记录线段长度是有原因的,并非$pre[i]$和$i$都可以。如果用$pre[i]$也即是左端点记录线段长度的话,对于每组查询而言,区间内每个满足条件的点,它所代表的线段的右端点都不会超过当前的$r$,因此可以用来直接求最小值。但是!!假如是用$i$也即是右端点来记录线段长度的话,区间内每个满足条件的点,它所代表的线段的左端点都可能会超过当前的$l$,那个点就不能用来求最小值,但很显然计算的时候会把这个点计入,所以这样得到的结果可能就是错的!!
参考博客:
https://www.cnblogs.com/zjl192628928/p/11661714.html
牛客练习赛53 E-老瞎眼pk小鲜肉(思维+线段树+离线)的更多相关文章
- 牛客练习赛53 E 老瞎眼 pk 小鲜肉 (线段树,思维)
链接:https://ac.nowcoder.com/acm/contest/1114/E来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语言1048 ...
- 牛客练习赛53 (E 老瞎眼 pk 小鲜肉) 线段树+离线
考试的时候切的,类似HH的项链~ code: #include <bits/stdc++.h> #define ll long long #define M 500003 #define ...
- 牛客练习赛53 D 德育分博弈政治课 (思维建图,最大流)
牛客练习赛53 D德育分博弈政治课 链接:https://ac.nowcoder.com/acm/contest/1114/D来源:牛客网 题目描述 德育分学长最近玩起了骰子.他玩的骰子不同,他的骰子 ...
- 牛客练习赛53 A 超越学姐爱字符串 (DP)
牛客练习赛53 超越学姐爱字符串 链接:https://ac.nowcoder.com/acm/contest/1114/A来源:牛客网 超越学姐非常喜欢自己的名字,以至于英文字母她只喜欢" ...
- 牛客练习赛53 A-E
牛客联系赛53 A-E 题目链接:Link A 超越学姐爱字符串 题意: 长度为N的字符串,只能有C,Y字符,且字符串中不能连续出现 C. 思路: 其实就是DP,\(Dp[i][c]\) 表示长度为 ...
- 牛客练习赛44 B:小y的线段
链接:https://ac.nowcoder.com/acm/contest/634/B 来源:牛客网 题目描述 给出\(n\)条线段,第\(i\)条线段的长度为\(a_i\),每次可以从第\(i\) ...
- 【牛客练习赛53】A-超越学姐爱字符串
// 题目地址:https://ac.nowcoder.com/acm/contest/1114/A /* 找规律(碰运气) n:1 = 2 n:2 = 3 n:3 = 5 n:4 = 8 ... d ...
- 牛客练习赛53 B 美味果冻
链接:https://ac.nowcoder.com/acm/contest/1114/B来源:牛客 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语言10485 ...
- 牛客练习赛33 D tokitsukaze and Inverse Number (树状数组求逆序对,结论)
链接:https://ac.nowcoder.com/acm/contest/308/D 来源:牛客网 tokitsukaze and Inverse Number 时间限制:C/C++ 1秒,其他语 ...
随机推荐
- ssh升级以及ssh: symbol lookup error: ssh: undefined symbol: EVP_aes_128_ctr错误处理
1.解压安装openssl包:(不能卸载openssl,否则会影响系统的ssl加密库文件,除非你可以做两个软连接libcryto和libssl) # tar -zxvf openssl-1.0.1.t ...
- JDK1.7-HashMap原理
JDK1.7 HashMap 如何在源码上添加自己的注释 打开jdk下载位置 解压src文件夹,打开idea,ctrl+shift+alt+s打开项目配置 选择jdk版本1.7,然后点击Sourcep ...
- 【C++】《C++ Primer 》第十三章
第十三章 拷贝控制 定义一个类时,需要显式或隐式地指定在此类型地对象拷贝.移动.赋值和销毁时做什么. 一个类通过定义五种特殊的成员函数来控制这些操作.即拷贝构造函数(copy constructor) ...
- 【Flutter】容器类组件之剪裁
前言 Flutter中提供了一些剪裁函数,用于对组件进行剪裁. 剪裁Widget 作用 ClipOval 子组件为正方形时剪裁为内贴圆形,为矩形时,剪裁为内贴椭圆 ClipRRect 将子组件剪裁为圆 ...
- maven生命周期与插件
目录 Maven生命周期 clean default site 命令与对应周期 插件与绑定 插件目标 插件绑定 内置绑定 自定义绑定 插件配置 本文主要是针对<maven实战>书中关键知识 ...
- C语言逗号运算符(C语言学习笔记)
什么是逗号运算符 逗号运算符 逗号运算符是指在C语言中,多个表达式可以用逗号分开,其中用逗号分开的表达式的值分别结算,但整个表达式的值是最后一个表达式的值. 用法 多个变量赋值 原因:"=& ...
- misc刷题
前言:听说misc打得好,头发多不了 kali自带的字典: cd /usr/share/wordlists/ 字典网站:http://contest-2010.korelogic.com/wordli ...
- mount: /dev/sdxx already mounted or /xxxx busy解决方法
异常现象: 解决方法: 1. 輸入root的密碼,進入單用戶2. 重新掛載/目錄,使其變為可讀可寫 # mount –o rw,remount / 3. 修改/etc/fstab文件 ...
- 03--Docker 容器和镜像常用命令
一.帮助命令 docker version docker info docker --help =====================镜像命令=========================== ...
- IDEA安装codota插件和使用,开发人员的知心伙伴
打开IDEA 点击左上角的File之后,如下图 成功后如图所示