记录一下一个新学的线段树基础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. SSM整合,快速新建javaWeb项目

    整合前需要了解: spring和springmvc包扫描的注意事项 Spring applicationContext.xml (父容器),SpringMVC springmvc-servlet.xm ...

  2. jbd2的死锁分析

    已经运行多年的jbd2,它还是死锁了 背景:这个是在centos7的环境上复现的,内核版本为3.10.0-957.27.2.el7 下面列一下我们是怎么排查并解这个问题的. 一.故障现象 oppo云内 ...

  3. 深入理解 Spring 事务:入门、使用、原理

    大家好,我是树哥. Spring 事务是复杂一致性业务必备的知识点,掌握好 Spring 事务可以让我们写出更好地代码.这篇文章我们将介绍 Spring 事务的诞生背景,从而让我们可以更清晰地了解 S ...

  4. 【ARK UI】HarmonyOS 从相册选择图片并显示到Image组件上

    ​ 参考资料 [Harmony OS][ARK UI]ETS 上下文基本操作 [Harmony OS][ARK UI]ets使用startAbility或startAbilityForResult方式 ...

  5. OpenJ_Bailian - 3424 Candies (差分约束)

    题面 During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teache ...

  6. 使用VS Code 搭建 platformio 平台

    一.需要的资源网站 arduino GitHub:https://github.com/arduino espressif GitHub:https://github.com/espressif pl ...

  7. day01-GUI坦克大战01

    JavaGUI-坦克大战 1.Java绘图坐标体系 坐标体系介绍:下图说明了一个Java坐标体系.坐标原点位于左上角,以像素为单位.在Java坐标体系中,第一个是x坐标,表示当前位置为水平方向,距离坐 ...

  8. KingbaseES 与 Oracle 用户口令管理与资源管理

    一.概述 KingbaseES可以对用户口令与用户占用资源进行必要的管理.其管理方式,在这里与Oracle数据库进行参考比较. KingbaseES 使用扩展插件建立的系统参数,这组参数可以对数据库资 ...

  9. Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):4、Maven项目转换与pom.xml配置

    文章目录: Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):1.JIRA账号注册 Taurus.MVC-Java 版本打包上传到Maven中央仓库(详细过程):2.PGP ...

  10. 使用Inno Setup 制作软件安装包详细教程(与开发语言无关)

    前言:关于如何制作一个软件安装包的教程,与编程语言无关.以下,请看详情~ 1.下载Inno Setup,下载地址:https://jrsoftware.org/isinfo.php 2.下载最新版本即 ...