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. Codeforces Round #271 (Div. 2) D. Flowers (递推 预处理)

    We saw the little game Marmot made for Mole's lunch. Now it's Marmot's dinner time and, as we all kn ...

  2. has实现 更新视图但不重新加载页面原理

    URL中#符号本身以及它的字符称之为hash,可以通过window.location.hash获取.hash具有如下特点: 1.has虽然出现在URL中,但不会被包括在http请求中.因此,改变has ...

  3. Eclipse插件开发中的选择监听机制(Selection Provider-Listener)

    Eclipse插件开发中的选择监听机制(Selection Provider-Listener) 监听机制是eclipse插件开发或rcp应用开发中经常使用的技术,比方点击TableViewer或Tr ...

  4. linux启动基本流程

    linux启动序列 1.CPU初始化    CPU自身初始化.从某个固定位置(0xfffffff0)取指令并运行,该指令为跳转指令.跳转到BIOS代码的首部. 2.装载BIOS    BIOS被固化在 ...

  5. MessageBox.Show

    MessageBox.Show()共有21中重载方法.现将其常见用法总结如下: .MessageBox.Show("Hello~~~~"); 最简单的,只显示提示信息. .Mess ...

  6. POJ 1330 LCA裸题~

    POJ 1330 Description A rooted tree is a well-known data structure in computer science and engineerin ...

  7. Tarjan求桥

    传送门(poj3177) 这道题是Tarjan求桥的模板题.大意是要求在原图上加上数量最少的边,使得整张图成为一个边双联通分量. 具体的做法是,先在图中求出所有的桥,之后把边双联通分量缩成点,这样的话 ...

  8. bzoj4407

    http://www.lydsy.com/JudgeOnline/problem.php?id=4407 以前写过一次线性筛 发现不是很理解 写了个欧拉筛的 t了 其实每次推式子,都会先推出一组的解法 ...

  9. 34.无废话ExtJs 入门教程十八[树:TreePanel]

    转自:https://www.cnblogs.com/iamlilinfeng/archive/2012/06/28/2566350.html 1. <!DOCTYPE html PUBLIC ...

  10. Newtonsoft.Json序列化日期时间去T的几种方式。

    原文地址:MVC web api 返回JSON的几种方式,Newtonsoft.Json序列化日期时间去T的几种方式. http://www.cnblogs.com/wuball/p/4231343. ...