ZOJ Monthly, August 2012 3633 Alice's present

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3633

题意:给一个数列,每次询问一个区间第一次出现两次的位置(从右向左)。

思路:开一个数组,记录当前值的左边第一次出现的位置。然后用线段树维护这个数组的区间最大值就行了。

View Code
#include<stdio.h>
#include<string.h>
#include<map>
#include<utility>
#include<algorithm>
using namespace std;
const int maxn = 500005;
int as[maxn<<2],bs[maxn],cs[maxn],Hash[maxn],ds[maxn];
void build(int rt,int l,int r)
{
    int m = (l + r) >> 1;
    if(l==r){
        as[rt] = bs[l];
        return;
    }
    build(rt<<1,l,m);
    build(rt<<1|1,m+1,r);
    as[rt]=max(as[rt<<1],as[rt<<1|1]);
}
int query(int rt,int l,int r,int L,int R)
{
    int m = (l + r) >> 1;
    int k = 0,t = 0;
    if(L<=l && r<=R)
        return as[rt];
    if(L<=m)k = query(rt<<1,l,m,L,R);
    if(R>m )t = query(rt<<1|1,m+1,r,L,R);
    return max(k,t);
}
int bitser(int x,int n)
{
    int l = 1,r = n,m;
    while(l < r){
        m = (l + r) >> 1;
        if(bs[m]==x)return m;
        if(bs[m]> x)r = m - 1;
        else l = m + 1;
    }return l;
}
int main()
{
    int i,j,k,l,r,n;
    while(scanf("%d",&n)==1){
        for(i = 1; i <= n; ++ i){
            scanf("%d",&k);
            cs[i] = k;
            bs[i] = k;
            ds[i] = k;
        }
        sort(bs+1,bs+n+1);
        for(i = 1; i <= n; ++ i)
        cs[i] = bitser(cs[i],n);
        for(i = 1; i <= n; ++ i)Hash[i] = 0;
        for(i = 1; i <= n; ++ i){
            bs[i] = Hash[cs[i]];
            Hash[cs[i]] = i;
        }
        build(1,1,n);
        scanf("%d",&k);
        while(k--){
            scanf("%d%d",&l,&r);
            j = query(1,1,n,l,r);
            if(!j||j<l)puts("OK");
            else printf("%d\n",ds[j]);
        }
        puts("");
    }
    return 0;
}

posted on 2012-08-26 21:32  aigoruan  阅读(208)  评论(0)    收藏  举报

导航