luoojP1042 互不相同数

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

分析
虽然题目的来源是哈希但是我写的是线段树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] 具有单调性

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值