dutacm.club_1094_等差区间_(线段树)(RMQ算法)
1094: 等差区间
Total Submissions:843 Accepted:89
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算法)的更多相关文章
- BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针
BZOJ_4653_[Noi2016]区间_线段树+离散化+双指针 Description 在数轴上有 n个闭区间 [l1,r1],[l2,r2],...,[ln,rn].现在要从中选出 m 个区间, ...
- BZOJ_2124_等差子序列_线段树+Hash
BZOJ_2124_等差子序列_线段树+Hash Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pL ...
- CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]
题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809 Bobo has a balanced parenthesis sequenc ...
- [bzoj2124]等差子序列_线段树_hash
等差子序列 bzoj-2124 题目大意:给定一个1~n的排列,问是否存在3个及以上的位置上的数构成连续的等差子序列. 注释:$1\le n\le 10^4$. 想法:这题就相当于是否存在3个数i,j ...
- BZOJ_4636_蒟蒻的数列_线段树+动态开点
BZOJ_4636_蒟蒻的数列_线段树+动态开点 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将 ...
- BZOJ_3252_攻略_线段树+dfs序
BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...
- BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心
BZOJ_1826_[JSOI2010]缓存交换 _线段树+贪心 Description 在计算机中,CPU只能和高速缓存Cache直接交换数据.当所需的内存单元不在Cache中时,则需要从主存里把数 ...
- BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树
BZOJ_1828_[Usaco2010 Mar]balloc 农场分配_线段树 Description Input 第1行:两个用空格隔开的整数:N和M * 第2行到N+1行:第i+1行表示一个整数 ...
- BZOJ_1858_[Scoi2010]序列操作_线段树
BZOJ_1858_[Scoi2010]序列操作_线段树 Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是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 ...
- has实现 更新视图但不重新加载页面原理
URL中#符号本身以及它的字符称之为hash,可以通过window.location.hash获取.hash具有如下特点: 1.has虽然出现在URL中,但不会被包括在http请求中.因此,改变has ...
- Eclipse插件开发中的选择监听机制(Selection Provider-Listener)
Eclipse插件开发中的选择监听机制(Selection Provider-Listener) 监听机制是eclipse插件开发或rcp应用开发中经常使用的技术,比方点击TableViewer或Tr ...
- linux启动基本流程
linux启动序列 1.CPU初始化 CPU自身初始化.从某个固定位置(0xfffffff0)取指令并运行,该指令为跳转指令.跳转到BIOS代码的首部. 2.装载BIOS BIOS被固化在 ...
- MessageBox.Show
MessageBox.Show()共有21中重载方法.现将其常见用法总结如下: .MessageBox.Show("Hello~~~~"); 最简单的,只显示提示信息. .Mess ...
- POJ 1330 LCA裸题~
POJ 1330 Description A rooted tree is a well-known data structure in computer science and engineerin ...
- Tarjan求桥
传送门(poj3177) 这道题是Tarjan求桥的模板题.大意是要求在原图上加上数量最少的边,使得整张图成为一个边双联通分量. 具体的做法是,先在图中求出所有的桥,之后把边双联通分量缩成点,这样的话 ...
- bzoj4407
http://www.lydsy.com/JudgeOnline/problem.php?id=4407 以前写过一次线性筛 发现不是很理解 写了个欧拉筛的 t了 其实每次推式子,都会先推出一组的解法 ...
- 34.无废话ExtJs 入门教程十八[树:TreePanel]
转自:https://www.cnblogs.com/iamlilinfeng/archive/2012/06/28/2566350.html 1. <!DOCTYPE html PUBLIC ...
- Newtonsoft.Json序列化日期时间去T的几种方式。
原文地址:MVC web api 返回JSON的几种方式,Newtonsoft.Json序列化日期时间去T的几种方式. http://www.cnblogs.com/wuball/p/4231343. ...