1094: 等差区间

Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:843   Accepted:89

[Submit][Status][Discuss]

Description

已知一个长度为 nn 的数组 a[1],a[2],…,a[n],我们进行 qq 次询问,每次询问区间 a[l],a[l+1],…,a[r−1],a[r],数字从小到大排列后,是否会形成等差数列。等差数列的定义为,数列相邻两项(后一项减去前一项)的差值相等。

Input

本题有多组输入数据。

每组输入数据第一行输入两个正整数 nn 和 qq。第二行输入 nn 个正整数 a[1],a[2],…,a[n]。最后输入 qq 行,每行两个数字 l,rl,r(1≤l≤r≤n),表示询问区间 a[l],…,a[r]。

1≤n,q≤10^5,1≤a[i]≤10^6

Output

对于每组询问输出一行,如果形成等差数列,输出“Yes ”,否则输出“No”(不含引号)。

Sample Input

5 5
3 1 5 2 4
1 3
4 5
1 4
3 4
2 2

Sample Output

Yes
Yes
No
Yes
Yes 题意:给定一个n位数列,q条查询[l,r],询问子序列[l--r]排序后是否为等差数列。 看题解说用的什么 RMQ求区间最大最小 但是没有学过,过些天再补。我用线段树来代替的求最大最小值。 思路:一个区间要是等差数列:1.所有数相等;2.所有数不等,且求公差,满足g*(r-l)==maxn-minn。 然后就是公差,我反正是没想到。求这个序列所有相邻两项差的最大公约数,结果即为公差,求公差也需要在线段树中进行,不能枚举。 同时,需要记录当前这个数上一次出现的位置。 线段树中维护区间:最大值,最小值,公差,序列中所有出现过的数上一次出现的位置的最大值(因为第2中情况需要所有数不同)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define N 100005 int num[N]; struct Node
{
int l,r;
int maxn,minn,g,lef;
} tree[N<<]; int Gcd(int a,int b)
{
if(a==||b==)
return ;
if(a<b)
{
int t=a;
a=b;
b=t;
}
if(a%b==)
return b;
return Gcd(b,a%b);
} int cha[N],loc[N*],last[N];
void build(int l,int r,int rt)
{
tree[rt].maxn=tree[rt].minn=;
tree[rt].l=l;
tree[rt].r=r;
if(l==r)
{
tree[rt].maxn=num[l];
tree[rt].minn=num[l];
tree[rt].g=-;
tree[rt].lef=last[l];
return;
}
int mid=(l+r)>>;
build(lson);
build(rson);
tree[rt].maxn=max(tree[rt<<].maxn,tree[rt<<|].maxn);
tree[rt].minn=min(tree[rt<<].minn,tree[rt<<|].minn);
if(tree[rt<<].l==tree[rt<<].r&&tree[rt<<|].l==tree[rt<<|].r) //建树时求出所有子节点数大于1的结点的公差
tree[rt].g=abs(num[tree[rt<<].r]-num[tree[rt<<|].l]);
else if(tree[rt<<|].l==tree[rt<<|].r)
tree[rt].g=Gcd(tree[rt<<].g,abs(num[tree[rt<<].r]-num[tree[rt<<|].l]));
else
tree[rt].g=Gcd(Gcd(tree[rt<<].g,abs(num[tree[rt<<].r]-num[tree[rt<<|].l])),tree[rt<<|].g);
tree[rt].lef=max(tree[rt<<].lef,tree[rt<<|].lef);
} struct Res
{
int maxn,minn,g,lef;
Res(){}
Res(int a,int b,int g1,int le)
{
maxn=a;
minn=b;
g=g1;
lef=le;
}
}; /*Res deal(Res a,Res b)
{
Res tmp(max(a.maxn,b.maxn),min(a.minn,b.minn));
return tmp;
}*/ Res query(int L,int R,int l,int r,int rt)
{
if(L==l&&r==R)
{
Res tmp(tree[rt].maxn,tree[rt].minn,tree[rt].g,tree[rt].lef);
return tmp;
}
int mid=(l+r)>>;
if(L>mid)
return query(L,R,rson);
else if(R<=mid)
return query(L,R,lson);
else
{
Res r1=query(L,mid,lson);
Res r2=query(mid+,R,rson);
Res r3;
r3.maxn=max(r1.maxn,r2.maxn);
r3.minn=min(r1.minn,r2.minn);
if(r1.g==-&&r2.g==-) //查询时需注意,若查到叶子结点,其公约数为-1,需特殊处理
r3.g=abs(num[mid]-num[mid+]);
else if(r1.g==-)
r3.g=Gcd(abs(num[mid]-num[mid+]),r2.g);
else if(r2.g==-)
r3.g=Gcd(abs(num[mid]-num[mid+]),r1.g);
else
r3.g=Gcd(r1.g,Gcd(abs(num[tree[rt<<].r]-num[tree[rt<<|].l]),r2.g));
r3.lef=max(r1.lef,r2.lef);
return r3;
}
} int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF)
{
//memset(tree,0,sizeof(tree));
memset(loc,,sizeof(loc));
for(int i=; i<=n; i++)
{
scanf("%d",&num[i]);
if(loc[num[i]]==)
last[i]=;
else
last[i]=loc[num[i]];
loc[num[i]]=i;
if(i>)
cha[i-]=abs(num[i]-num[i-]);
} build(,n,);
while(q--)
{
int ll,rr;
scanf("%d%d",&ll,&rr);
Res tm=query(ll,rr,,n,);
int maxn=tm.maxn;
int minn=tm.minn;
int g=tm.g;
int lef=tm.lef;
//cout<<maxn<<' '<<minn<<' '<<g<<' '<<lef<<endl;
if(minn==maxn)
{
printf("Yes\n");
continue;
}
if(lef<ll&&(g*(rr-ll)==maxn-minn))
printf("Yes\n");
else
printf("No\n");
}
}
return ;
}
 RMQ(Range Minimum/Maximum Query),即区间最值查询。一种动态规划。思路和线段树的一样。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stdlib.h>
using namespace std;
#define N 100005 int dpMax[N][],dpMin[N][],dpG[N][],dpLeft[N][],n,loc[N*]; int Gcd(int a,int b)
{
if(a==||b==)
return ;
if(a<b)
{
int tmp=a;
a=b;
b=tmp;
}
if(a%b==)
return b;
return Gcd(b,a%b);
} void RMQ()
{
for(int j=; j<=; j++)
for(int i=; i<=n; i++)
if((<<j)+i-<=n)
{
dpMax[i][j]=max(dpMax[i][j-],dpMax[i+(<<j-)][j-]);
dpMin[i][j]=min(dpMin[i][j-],dpMin[i+(<<j-)][j-]);
dpLeft[i][j]=max(dpLeft[i][j-],dpLeft[i+(<<j-)][j-]);
if(j==)
dpG[i][j]=abs(dpMin[i][]-dpMin[i+][]);
else
dpG[i][j]=Gcd(dpG[i][j-],Gcd(abs(dpMin[i+(<<j-)][]-dpMin[i+(<<j-)-][]),dpG[i+(<<j-)][j-]));
}
} int main()
{
//cout<<log2(0)<<endl;
int q;
while(scanf("%d%d",&n,&q)!=EOF)
{
memset(loc,,sizeof(loc));
for(int i=; i<=n; i++)
{
scanf("%d",&dpMin[i][]);
dpMax[i][]=dpMin[i][];
dpG[i][]=-;
if(loc[dpMin[i][]]==)
dpLeft[i][]=;
else
dpLeft[i][]=loc[dpMin[i][]];
loc[dpMin[i][]]=i;
}
RMQ();
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
int k=log2(r-l+);
int maxn=max(dpMax[l][k],dpMax[r-(<<k)+][k]);
int minn=min(dpMin[l][k],dpMin[r-(<<k)+][k]);
int left=max(dpLeft[l][k],dpLeft[r-(<<k)+][k]);
int g=abs(dpMin[l][]-dpMin[r][]);
if(r-l>)
g=Gcd(g,Gcd(dpG[l][k],dpG[r-(<<k)+][k]));
//cout<<maxn<<' '<<minn<<' '<<g<<' '<<left<<endl;
if(maxn==minn)
printf("Yes\n");
else
{
if(left<l&&maxn-minn==(r-l)*g)
printf("Yes\n");
else
printf("No\n");
}
}
}
return ;
}
 

dutacm.club_1094_等差区间_(线段树)(RMQ算法)的更多相关文章

  1. BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针

    BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间, ...

  2. BZOJ_2124_等差子序列_线段树+Hash

    BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...

  3. CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]

    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809 Bobo has a balanced parenthesis sequenc ...

  4. [bzoj2124]等差子序列_线段树_hash

    等差子序列 bzoj-2124 题目大意:给定一个1~n的排列,问是否存在3个及以上的位置上的数构成连续的等差子序列. 注释:$1\le n\le 10^4$. 想法:这题就相当于是否存在3个数i,j ...

  5. BZOJ_4636_蒟蒻的数列_线段树+动态开点

    BZOJ_4636_蒟蒻的数列_线段树+动态开点 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将 ...

  6. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  7. BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心

    BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...

  8. BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树

    BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树 Description Input 第1行:两个用空格隔开的整数:N和M * 第2行到N+1行:第i+1行表示一个整数 ...

  9. BZOJ_1858_[Scoi2010]序列操作_线段树

    BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询 ...

随机推荐

  1. IOS推断是否安装微信qq

    BOOL weicaht = [[UIApplicationsharedApplication]canOpenURL:[NSURLURLWithString:@"mqqapi://" ...

  2. 使用requireJS的shim參数,完毕jquery插件的载入

    没有requireJS框架之前,假设我们想使用jquery框架,会在HTML页面中通过<script>标签载入.这个时候jquery框架生成全局变量$和jQuery等全局变量.假设项目中引 ...

  3. Django打造大型企业官网(三)

    四.前端首页 4.1.导航条实现 (1)templates/new/index.html <!DOCTYPE html> <html lang="en"> ...

  4. 记录一次node中台转发表单上传文件到后台过程

    首发掘金 记录一次node中台转发表单上传文件到后台过程 本篇跟掘金为同一个作者leung   公司几个项目都是三层架构模式即前台,中台(中间层),后台.前台微信端公众号使用vue框架,后台管理前端使 ...

  5. 2016/2/19 position: fixed absolute relative z-index float 半透明效果

    一.position:fixed 锁定位置(相对于浏览器的位置),例如有些网站的右下角的弹出窗口.      显示效果  无论滚动条怎么移动  都固定在显示页面的一个位置不动 二.position:a ...

  6. 【OI】对拍

    对拍的方法是先用生成器生成几组随机数据,然后用暴力算法和当前算法对比结果来确保正确性. 数据生成器: 引入cstdlib与ctime两个库,然后通过srand初始化随机数: srand(time(0) ...

  7. Notification操作大全

    目录 一:普通的Notification Notification 的基本操作 给 Notification 设置 Action 更新 Notification 取消 Notification 设置 ...

  8. go语言---defer

    go语言---defer https://blog.csdn.net/cyk2396/article/details/78885135 defer 是在函数退出前调用,多个defer遵循 先进后出 的 ...

  9. [Codeforces 986E] Prince's Problem

    [题目链接] https://codeforces.com/contest/986/problem/E [算法] X到Y的路径积 , 可以转化为X到根的路径积乘Y到根的路径积 , 除以LCA到根的路径 ...

  10. XML消息解析_php

    初识php——微信消息处理 <?php $test = new weixin(); $test->Message(); class weixin{ public function Mess ...