Codeforces 622C Not Equal on a Segment【思维预处理+二分】

本文介绍了一种解决特定区间内查找不等于指定值的元素的算法问题,通过预处理和二分查找技术实现了高效查询。

C. Not Equal on a Segment
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given array a with n integers and m queries. The i-th query is given with three integers li, ri, xi.

For the i-th query find any position pi (li ≤ pi ≤ ri) so that api ≠ xi.

Input

The first line contains two integers n, m (1 ≤ n, m ≤ 2·105) — the number of elements in a and the number of queries.

The second line contains n integers ai (1 ≤ ai ≤ 106) — the elements of the array a.

Each of the next m lines contains three integers li, ri, xi (1 ≤ li ≤ ri ≤ n, 1 ≤ xi ≤ 106) — the parameters of the i-th query.

Output

Print m lines. On the i-th line print integer pi — the position of any number not equal to xi in segment [li, ri] or the value  - 1 if there is no such number.

Examples
Input
6 4
1 2 1 1 3 5
1 4 1
2 6 2
3 4 1
3 4 2
Output
2
6
-1
4

题目大意:

给你一个长度为N的序列Ai,有m个查询,每个查询三个元素:l,r,x,表示我们希望在序列区间【l,r】中,找到一个位子p,使得Ap!=x.

找到任意一个即可,如果找不到,输出-1.


思路:


1、首先我们设定<vector>mp【i】,我们将数字i所在的位子按照从小到大的顺序存入到这里.然后我们对于每个查询,因为数组具有单调性,我们可以二分第一个x出现的位子L.

①我们如果L是找不到的,那么对应肯定结果输出l即可。

②如果我们可以找到一个位子L,但是L!=l,那么对应结果肯定输出l即可。

③如果我们可以找到一个位子L,使得L==l,那么我们要查询位子L的右边,第一个不等于x的数的位子即可,如果这个位子<=R,那么输出这个位子,相反输出-1.


2、对于上述③中的查询,查询a【L】右边第一个不等于a【L】的位子,我们设定pos【i】来完成这个任务,那么对应O(n)从n扫到1预处理这个数组即可。

具体实现参考代码,并不复杂。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int >mp[1205000];
int a[205000];
int pos[205000];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=120000;i++)mp[i].clear();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),mp[a[i]].push_back(i);
        int nex=n;
        for(int i=n;i>=1;i--)
        {
            if(i==n)pos[i]=n+1;
            else
            {
                if(a[i]==a[i+1])pos[i]=pos[i+1],nex=i;
                else pos[i]=nex,nex=i;
            }
        }
        while(m--)
        {
            int L,R,x;
            scanf("%d%d%d",&L,&R,&x);
            int anspos=-1;
            int l=0;
            int r=mp[x].size()-1;
            while(r-l>=0)
            {
                int mid=(l+r)/2;
              //  printf("%d %d\n",mid,mp[x][mid]);
                if(mp[x][mid]>=L)
                {
                    anspos=mp[x][mid];
                    r=mid-1;
                }
                else
                {
                    l=mid+1;
                }
            }
            if(anspos==-1)printf("%d\n",L);
            else
            {
                if(anspos!=L)printf("%d\n",L);
                else
                {
                    if(pos[anspos]<=R)printf("%d\n",pos[anspos]);
                    else printf("-1\n");
                }
            }
        }
    }
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值