1042: 互不相同数
时间限制: 1 Sec内存限制: 128 MB
提交: 59解决: 33
题目描述
数列A1,A2, …… ,AN,Q 个询问(Li;Ri),ALi ,ALi+1, ……, ARi 是否互不相同。
输入
第1 行,2 个整数N,Q,
第2 行,N 个整数A1,A2, …… ,AN
Q 行,每行2 个整数Li,Ri
输出
对每个询问输出一行,“Yes” 或者“No”
样例输入
4 2
1 2 3 2
1 3
2 4
样例输出
Yes
No
提示
对于50% 的数据,N, Q<=10^3
对于100% 的数据,1<= N;Q <= 10^5, 1<= Ai<= N; 1 <= Li <= Ri <= N
提交: 59解决: 33
题目描述
数列A1,A2, …… ,AN,Q 个询问(Li;Ri),ALi ,ALi+1, ……, ARi 是否互不相同。
输入
第1 行,2 个整数N,Q,
第2 行,N 个整数A1,A2, …… ,AN
Q 行,每行2 个整数Li,Ri
输出
对每个询问输出一行,“Yes” 或者“No”
样例输入
4 2
1 2 3 2
1 3
2 4
样例输出
Yes
No
提示
对于50% 的数据,N, Q<=10^3
对于100% 的数据,1<= N;Q <= 10^5, 1<= Ai<= N; 1 <= Li <= Ri <= N
分析
虽然题目的来源是哈希但是我写的是线段树QwQ;
首先看到题目第一点就是说可以先预处理出最近的右端的相同点的点的位置这样之后就转还成了球去见最小值的问题;果断用线段树;
心得
注意注意模型之间的转换;要可以发现问题的本质。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int l,r,s;
}t[500005];
int sum[500005];
int a[500005];
int z[500005];
int n,q,l,r;
void build(int i,int l,int r){
t[i].l=l;t[i].r=r;
if(l==r){
t[i].s=sum[l];
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
t[i].s=min(t[i<<1].s,t[i<<1|1].s);
}
int query(int i,int l,int r){
if(t[i].l==l&&t[i].r==r)return t[i].s;
int mid=(t[i].l+t[i].r)>>1;
if(mid>=r)return query(i<<1,l,r);
else if(l>mid)return query(i<<1|1,l,r);
else return min(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
sum[i]=(2<<30)-1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(z[a[i]])sum[z[a[i]]]=i;
z[a[i]]=i;
}
build(1,1,n);
while(q--){
scanf("%d%d",&l,&r);
if(query(1,l,r)>r)printf("Yes\n");
else printf("No\n");
}
return 0;
}
给出的算法,Orz:
离线处理,把所有询问按L记录在对应点上。
对于每一个Ai,求出j使得Ai~Aj的数两两不同,且j最大。
记label[i] = j
对于每个捆绑在i上的询问,判断其右侧和j的关系,<= j 则“Yes”,否则“No”
如何快速求出label呢?
对于Ai~label[i] 和 Ai+1 ~ label[i + 1]是互不相同的。
当label[i+1] = label[i]
发现label[i] 具有单调性
离线处理,把所有询问按L记录在对应点上。
对于每一个Ai,求出j使得Ai~Aj的数两两不同,且j最大。
记label[i] = j
对于每个捆绑在i上的询问,判断其右侧和j的关系,<= j 则“Yes”,否则“No”
如何快速求出label呢?
对于Ai~label[i] 和 Ai+1 ~ label[i + 1]是互不相同的。
当label[i+1] = label[i]
发现label[i] 具有单调性
离线处理,把所有询问按L记录在对应点上。
对于每一个Ai,求出j使得Ai~Aj的数两两不同,且j最大。
记label[i] = j
对于每个捆绑在i上的询问,判断其右侧和j的关系,<= j 则“Yes”,否则“No”
如何快速求出label呢?
对于Ai~label[i] 和 Ai+1 ~ label[i + 1]是互不相同的。
当label[i+1] = label[i]
发现label[i] 具有单调性
离线处理,把所有询问按L记录在对应点上。
对于每一个Ai,求出j使得Ai~Aj的数两两不同,且j最大。
记label[i] = j
对于每个捆绑在i上的询问,判断其右侧和j的关系,<= j 则“Yes”,否则“No”
如何快速求出label呢?
对于Ai~label[i] 和 Ai+1 ~ label[i + 1]是互不相同的。
当label[i+1] = label[i]
发现label[i] 具有单调性
#include <iostream>
using namespace std;
int f[100001],a[100001];
bool b[100001];
int main () {
int n,q,i,j,l,r;
cin>>n>>q;
for (i=1;i<=n;i++){
cin>>a[i];
}
f[0]=1;
for (i=1;i<=n;i++){
b[a[i]]=1;
for (j=f[i-1]+1;j<=n;j++){
if (b[a[j]]&&j!=i){
f[i]=j-1;
break;
}
b[a[j]]=1;
}
if (j>n)f[i]=n;
b[a[i]]=0;
}
//for (i=1;i<=n;i++)cout<<f[i]<<' ';cout<<endl;
for (i=1;i<=q;i++){
cin>>l>>r;
if (f[l]>=r){
cout<<"Yes"<<endl;
}
else {
cout<<"No"<<endl;
}
}
return 0;
}