记录一下一个新学的线段树基础trick(真就小学生trick呗)

给你一个1到n的排列,你需要判断该排列内部是否存在一个3个元素的子序列(可以不连续),使得这个子序列是等差序列。\(n\) <=3e5

考虑等差数列的相关性质,对于一个3个数的等差数列,当 \(a_i\) 作为中间项可行时,当且仅当一定存在至少1个 \(k\),使得 \(a_i-k\) 这个元素在它的左边,\(a_i+k\) 这个元素在它的右边 (为了方便,这里的 \(k\)可以是负数)

那我们在顺序枚举 \(a_i\) 的过程中,不妨把用过的 \(a_i\) 标记成1,没用过的标记成零,然后对于所有范围内的 \(k\) 暴力判一遍

于是你就得到了一个 \(n^2\) 的暴力

大概长这样

//Talking to the moon
#include <bits/stdc++.h>
#define N 1000010
#define M 2000010
#define int long long
#define int_edge int to[M],val[M],nxt[M],head[N],cnt=0;
using namespace std;
int used[10010],a[10010];
//void add_edge(int x,int y ){to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
int read(){
int fu=1,ret=0;char ch;
for(;!isdigit(ch);ch=getchar())if(ch=='-')fu*=-1;
for(;isdigit(ch);ch=getchar())ret=(ret<<1)+(ret<<3)+ch-'0';
return ret*fu;
}
signed main()
{
int n=read(),ans=0;
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)
{
for(int j=1;a[i]-j>=1&&a[i]+j<=n;j++)
if(used[a[i]-j]!=used[a[i]+j]){ans=1;break;}
if(ans==1)break;
used[a[i]]=1;
}
if(ans==1)puts("YES");
else puts("NO");
return 0;
}

接下来是正解部分

我们发现正向考虑枚举 \(k\) 好像没有什么优化空间,而且题目也没让我们找 \(k\) ,那么正难则反,我们可以考虑作为中间项不可行的情况,即不存在 \(k\) 使得 \(a_i+k\) 和 \(a_i-k\) 的标记相同

那不就是回文串

于是我们的问题就变成了在值域上搞单点修改加区间判断是否回文

先不考虑修改,判断回文串其实是有一个非常优秀的朴素 Hash 算法的

就是考虑正反向各 Hash 一遍,然后判断查询区间的正反 Hash 值是否相等即可

然后 Hash 值是可以加减的

也就是说你把 a 在第1位的 hash 值加上 b 在第2位的 hash 值加起来就可以得到 ab 的 hash 值

那么修改就简单了,我们可以把这个 Hash 移到一棵线段树上(树状数组也可)

每个叶子节点存的是单点 hash 后的值

然后就可以支持单点修改,区间查询了

需要注意的是合并的时候需要把每一位乘上这一位对应的 hash 底数(比如131的多少次方什么的)

查询的时候也是

//Talking to the moon
#include <bits/stdc++.h>
#define N 300010
#define M 2000010
#define int unsigned long long
#define int_edge int to[M],val[M],nxt[M],head[N],cnt=0;
using namespace std;
int a[N],h[N];
//void add_edge(int x,int y ){to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
int read(){
int fu=1,ret=0;char ch;
for(;!isdigit(ch);ch=getchar())if(ch=='-')fu*=-1;
for(;isdigit(ch);ch=getchar())ret=(ret<<1)+(ret<<3)+ch-'0';
return ret*fu;
}
int ls(int x){return x*2;}
int rs(int x){return x*2+1;}
struct Seg1{
int tr[N*4];
void update(int nw,int l,int r,int x){
if(l==r){
tr[nw]++;
return;
}
int mid=(l+r)/2;
if(x<=mid)update(ls(nw),l,mid,x);
else update(rs(nw),mid+1,r,x);
tr[nw]=tr[ls(nw)]*h[r-mid]+tr[rs(nw)];
}
int query(int nw,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tr[nw]*h[y-r];
}
int mid=(l+r)/2,sum=0;
if(x<=mid)sum+=query(ls(nw),l,mid,x,y);
if(y>mid)sum+=query(rs(nw),mid+1,r,x,y);
return sum;
}
}S1;
struct Seg2{
int tr[N*4];
void update(int nw,int l,int r,int x){
if(l==r){
tr[nw]++;
return;
}
int mid=(l+r)/2;
if(x<=mid)update(ls(nw),l,mid,x);
else update(rs(nw),mid+1,r,x);
tr[nw]=tr[rs(nw)]*h[mid-l+1]+tr[ls(nw)];
}
int query(int nw,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tr[nw]*h[l-x];
}
int mid=(l+r)/2,sum=0;
if(x<=mid)sum+=query(ls(nw),l,mid,x,y);
if(y>mid)sum+=query(rs(nw),mid+1,r,x,y);
return sum;
}
}S2; signed main()
{
int n=read(),ans=0;
h[0]=1;for(int i=1;i<=n;i++)h[i]=h[i-1]*131;
for(int i=1;i<=n;i++)
{
a[i]=read();
int num=min(a[i]-1,n-a[i]),l=a[i]-num,r=a[i]+num;
if(S1.query(1,1,n,l,r)!=S2.query(1,1,n,l,r)){ans=1;break;}
S1.update(1,1,n,a[i]);S2.update(1,1,n,a[i]);
}
if(ans)puts("YES");
else puts("NO");
return 0;
}

CF452F等差子序列 & 线段树+hash查询区间是否为回文串的更多相关文章

  1. bzoj2124: 等差子序列线段树+hash

    bzoj2124: 等差子序列线段树+hash 链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2124 思路 找大于3的等差数列其实就是找等于 ...

  2. BZOJ 2124等差子序列 线段树&&hash

    [题目描述 Description] 给一个 1 到 N 的排列{Ai},询问是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len& ...

  3. BZOJ2124:等差子序列(线段树,hash)

    Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得A ...

  4. 牛客练习赛64 如果我让你查回文你还爱我吗 线段树 树状数组 manacher 计数 区间本质不同回文串个数

    LINK:如果我让你查回文你还爱我吗 了解到了这个模板题. 果然我不会写2333... 考试的时候想到了一个非常辣鸡的 线段树合并+莫队的做法 过不了不再赘述. 当然也想到了manacher不过不太会 ...

  5. HDU 4632 Palindrome subsequence(区间dp,回文串,字符处理)

    题目 参考自博客:http://blog.csdn.net/u011498819/article/details/38356675 题意:查找这样的子回文字符串(未必连续,但是有从左向右的顺序)个数. ...

  6. HDU - 5157 :Harry and magic string (回文树,求多少对不相交的回文串)

    Sample Input aca aaaa Sample Output 3 15 题意: 多组输入,每次给定字符串S(|S|<1e5),求多少对不相交的回文串. 思路:可以用回文树求出以每个位置 ...

  7. bzoj 2124 等差子序列 (线段树维护hash)

    2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 1922  Solved: 714[Submit][Status][Discuss ...

  8. BZOJ 2124: 等差子序列 线段树维护hash

    2124: 等差子序列 Description 给一个1到N的排列{Ai},询问是否存在1<=p1=3),使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一 ...

  9. [bzoj2124]等差子序列——线段树+字符串哈希

    题目大意 给一个1到N的排列\(A_i\),询问是否存在\(p_i\),\(i>=3\),使得\(A_{p_1}, A_{p_2}, ... ,A_{p_len}\)是一个等差序列. 题解 显然 ...

随机推荐

  1. RabbitMQ 入门系列:5、基础编码:交换机的进阶介绍及编码方式。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  2. Spring(一)- 初始 + DI+scope

    1.获取bean实例的三种方式 1.1 id 属性 1.1.1 jar <properties> <project.build.sourceEncoding>UTF-8< ...

  3. Linux之如何配置IPV6网络

    配置IPV6地址小笔记 #例题: 1)为server添加一个IPv6地址fd00:ba5e:ba11:10::10/64: 2)为client添加一个IPv6地址fd00:ba5e:ba11:10:: ...

  4. VM虚拟机安装

    VM虚拟机安装 1.安装vm虚拟机软件 1.1 双击打开虚拟机文件 1.2 根据向导安装 下一步 安装好了 不要着急点完成在 安装目录中有许可证. 1.3激活操作 2.虚拟机原理简介 3. 新建虚拟机 ...

  5. KingbaseES R6 集群手工配置VIP案例

    经常有用户问,V8R6集群搭建时没有配置VIP,搭建完成后,如何添加VIP?以下向大家介绍下手动添加VIP 的过程. 一.操作系统环境 操作系统(UOS): root@uos01:~# cat /et ...

  6. KingbaseES R3 集群pcp_attach_node 更新show pool_nodes中节点状态

    系统环境: 操作系统: [kingbase@node2 bin]$ cat /etc/centos-release CentOS Linux release 7.2.1511 (Core) 数据库: ...

  7. centos7部署Prometheus+Grafana

    一.安装Prometheus Server 请从 Prometheus 官方下载 linux 版的二进制压缩包.注意在下载前要选择操作系统为 linux. 执行下面的命令把 prometheus se ...

  8. 重复造轮子 SimpleMapper

    接手的项目还在用 TinyMapper 的一个早期版本用来做自动映射工具,TinyMapper 虽然速度快,但在配置里不能转换类型,比如 deleted 在数据库中用 0.1 表示,转换成实体模型时没 ...

  9. 2020年12月-第01阶段-前端基础-HTML CSS 项目阶段(一)

    品优购项目(一) 目标: 能会引入ico图标 能简单看懂网站优化的三大标签 能使用字体图标 ( 重点 ) 能说出我们css属性书写顺序 1. 品优购项目介绍 项目名称:品优购 项目描述:品优购是一个电 ...

  10. Java SE note1

    1.数据类型 基本类型 低------------------------------------------------->高 byte,short,char -> int -> ...