题目链接:HDU 5172 GTY‘s gay friends
题意:给出一串序列,询问[l,r]区间里是否存在1~l-r+1的一个排列。
思路:1~l-r+1的一个排列 等价于 [l,r]中元素互不相同且[l,r]区间和等于(1+len)*len/2(len=l-r+1)。
区间和可以用前缀和来处理。
元素互不相同,记录位置i上a[i]上次出现的位置记做pre[i],再用线段树来维护区间的pre最大值,若最大值小于l说明[l,r]中元素互不相同。(区间[l,r]中的每个pre[i]小于l说明区间元素互不相同,转化为区间pre的最大值小于l区间元素互不相同)
AC代码:
#include <stdio.h> #include <string.h> const int maxn=1000010; struct node{ int l,r; int max; int mid(){ return (l+r)>>1; } }; struct node tree[maxn<<2]; int sum[maxn],pre[maxn],pos[maxn];//pos[i] 数字i出现的最大位置。 //pre[i]位置i上a[i]上次出现的位置 int Max(int a,int b){ if(a>b) return a; return b; } void PushUp(int rt){ tree[rt].max=Max(tree[rt<<1].max,tree[rt<<1|1].max); } void build(int l,int r,int rt){ tree[rt].l=l; tree[rt].r=r; if(l==r){ tree[rt].max=pre[l]; return ; } int m=tree[rt].mid(); build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(rt); } int Query(int L,int R,int rt){ if(L<=tree[rt].l && tree[rt].r<=R){ return tree[rt].max; } int ret=-1; int m=tree[rt].mid(); if(R<=m) ret=Max(ret,Query(L,R,rt<<1)); else if(L>m) ret=Max(ret,Query(L,R,rt<<1|1)); else { ret=Max(ret,Query(L,R,rt<<1)); ret=Max(ret,Query(L,R,rt<<1|1)); } return ret; } int main() { int n,m,i,tmp,x; while(scanf("%d%d",&n,&m)!=EOF){ memset(sum,0,sizeof sum); memset(pre,0,sizeof pre); memset(pos,0,sizeof pos); for(i=1;i<=n;i++){ scanf("%d",&x); sum[i]=sum[i-1]+x; pre[i]=pos[x]; pos[x]=i; } build(1,n,1); int a,b; while(m--){ scanf("%d%d",&a,&b); int len=b-a+1; int s=sum[b]-sum[a-1]; int ok=Query(a,b,1); if(s==(len+1)*len/2 && ok<a) puts("YES"); else puts("NO"); } } return 0; }
HDU 5172 GTY's gay friends (预处理+线段树)
原文地址:http://blog.csdn.net/u012377575/article/details/43703489