Hdu 5172 GTY's gay friends

题目链接:点击打开链接

题目大意就是,给一段序列,长度为10^5,然后有10^5个询问,每次询问为一个区间,l为左边界,r为右边界,该区间是否为一个1到r-l+1的一个排列,即该区间是否满足包含1到r-l+1的所有元素。

分析一下,如果一个长度为n的区间包含从1到n的所有元素,那么在该区间之内,1到n的元素每个只出现一次,而且这个区间和应该为n(n+1)/2。第二个条件只需要处理前缀和即可,第一个条件则需要查重。

第一个我用的是线段树,每一个位置记录一下当前元素出现的上一个位置在哪里,然后以记录为元素建线段树,线段树的每个节点保存当前区间里重复出现的最后一个位置,对于查询只需要看重复位置是否出现在区间之内。

貌似出题人还提出一种哈希查重的方法,给1到n个元素随机一个哈希值,用集合元素的异或和作为哈希值,预处理出前n个元素的哈希值,然后o(1)查重...个人感觉存在满足哈希值相同且和相同的两个集合...用以自身为哈希值的方法交了一发,在一个大数据前面wa了,应该是个不稳定的方法...

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;
#define N 1000010
#define ls rt << 1
#define rs rt << 1 | 1
#define LL long long
struct node{
    int l,r;
    int pre;
}T[N<<2];
LL sum[N];
int pre[N],now[N];

void Pushup(int rt){
     T[rt].pre = max(T[ls].pre , T[rs].pre);
}

void build(int l,int r,int rt){
     T[rt].l = l;
     T[rt].r = r;
     if(l == r){
        T[rt].pre = now[l];
        return ;
     }
     int m = (l + r) >> 1;
     build(l,m,ls);
     build(m + 1,r,rs);
     Pushup(rt);
}

LL SUM(int l,int r){
    LL a = r - l + 1,ret;
    ret = ((LL)1+a)*a/(LL)2;
    return ret;
}

int query(int l,int r,int rt){
     if(l <= T[rt].l && T[rt].r <= r){
        return T[rt].pre;
     }
     int ret = -1;
     if( l <= T[ls].r ) ret = query(l,r,ls);
     if( r >= T[rs].l) ret = max(ret, query(l,r,rs));
     return ret;
}



int main()
{
    int n,m,t,l,r;
    LL ans;
    sum[0] = 0;
    while(~scanf("%d%d",&n,&m)){
        memset(pre,-1,sizeof(pre));
        for(int i=1;i<=n;i++){
            scanf("%d",&t);
            if(i==1){
                sum[i] = t;
            }
            else sum[i] = sum[i - 1] + (LL)t;
           // printf("%I64d ",sum[i]);//shan
            if(pre[t] == -1){
                now[i] = -1;
                pre[t] = i;
            }
            else{
                now[i] = pre[t];
                pre[t] = i;
            }
        }
        //printf("\n");// shan
        build(1,n,1);
        //printf("1\n");
        for(int i=0;i<m;i++){
            scanf("%d%d",&l,&r);
            ans = sum[r] - sum[l - 1];
            if(ans == SUM(l,r)){
            ans = query(l,r,1);
            if(ans >= l){
                printf("NO\n");
            }
            else {
                printf("YES\n");
            }
            }
            else{
                printf("NO\n");
            }
        }

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值