您的位置:首页 > 其它

hdu 5172 GTY's gay friends(线段树+前缀和)

2016-07-19 11:07 423 查看


GTY's gay friends

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1359    Accepted Submission(s): 347


Problem Description

GTY has n gay
friends. To manage them conveniently, every morning he ordered all his gay friends to stand in a line. Every gay friend has a characteristic value ai,
to express how manly or how girlish he is. You, as GTY's assistant, have to answer GTY's queries. In each of GTY's queries, GTY will give you a range [l,r] .
Because of GTY's strange hobbies, he wants there is a permutation [1..r−l+1] in [l,r].
You need to let him know if there is such a permutation or not.

 

Input

Multi test cases (about 3) . The first line contains two integers n and m ( 1≤n,m≤1000000 ),
indicating the number of GTY's gay friends and the number of GTY's queries. the second line contains n numbers seperated by spaces. The ith number ai ( 1≤ai≤n )
indicates GTY's ith gay
friend's characteristic value. The next m lines describe GTY's queries. In each line there are two numbers l and r seperated by spaces ( 1≤l≤r≤n ),
indicating the query range.

 

Output

For each query, if there is a permutation [1..r−l+1] in [l,r],
print 'YES', else print 'NO'.

 

Sample Input

8 5
2 1 3 4 5 2 3 1
1 3
1 1
2 2
4 8
1 5
3 2
1 1 1
1 1
1 2

 

Sample Output

YES
NO
YES
YES
YES
YES
NO

题意:问区间[L,R]中是不是1~R-L+1的某个排列

思路:贴官方题解

 一个区间是排列只需要区间和为\frac{len(len+1)}{2}​2​​len(len+1)​​(lenlen为区间长度),且互不相同,对于第一个问题我们用前缀和解决,对于第二个问题,预处理每个数的上次出现位置,记它为pre,互不相同即区间中pre的最大值小于左端点,使用线段树或Sparse
Table即可在O(n)/O(nlogn)O(n)/O(nlogn)的预处理后 O(logn)/O(1)O(logn)/O(1)回答每个询问.不过我们还有更简单的hash做法,对于[1..n][1..n]中的每一个数随机一个64位无符号整型作为它的hash值,一个集合的hash值为元素的异或和,预处理[1..n][1..n]的排列的hash和原序列的前缀hash异或和,就可以做到线性预处理,O(1)O(1)回答询问.

代码:先贴个RMQ MLE的代码..

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1000005
int a
,b
,pre
;
int dp
[20];
long long sum
;
void makermq(int n)
{
for(int i=1; i<=n; i++)
dp[i][0]=b[i];
for(int j=1; (1<<j)<=n; j++)
{
for(int i=1; i+(1<<j)-1<=n; i++)
{
dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int getmax(int s,int t)
{
int k=(int)(log(t-s+1.0)/log(2.0));
return max(dp[s][k],dp[t-(1<<k)+1][k]);
}
int main()
{
int n,m;
int l,r;
while(~scanf("%d %d",&n,&m))
{
memset(pre,0,sizeof(pre));
sum[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i]=pre[a[i]];
pre[a[i]]=i;
sum[i]=sum[i-1]+a[i];
}
makermq(n);
while(m--)
{
scanf("%d %d",&l,&r);
int num=getmax(l,r);
int len=r-l+1;
if(sum[r]-sum[l-1]==len*(len+1)/2&&num<l) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}

正解:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 1000005
int a
,b
,pre
;
int tree[N<<2];
long long sum
;
int Max(int a,int b)
{
return a>b?a:b;
}
void pushup(int root)
{
tree[root]=Max(tree[root<<1],tree[root<<1|1]);
}
void build(int root,int l,int r)
{
if(l==r)
{
tree[root]=b[l];
return;
}
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
pushup(root);
}
int query(int root,int l,int r,int pl,int pr)
{
if(l>=pl&&r<=pr)
return tree[root];
int mid=(l+r)>>1;
int ans=-1;
if(mid>=pl) ans=Max(ans,query(root<<1,l,mid,pl,pr));
if(mid<pr) ans=Max(ans,query(root<<1|1,mid+1,r,pl,pr));
return ans;
}
int main()
{
int n,m;
int l,r;
while(~scanf("%d %d",&n,&m))
{
memset(pre,0,sizeof(pre));
sum[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
b[i]=pre[a[i]];
pre[a[i]]=i;
sum[i]=sum[i-1]+a[i];
}
build(1,1,n);
while(m--)
{
scanf("%d %d",&l,&r);
int ans=query(1,1,n,l,r);
long long len=r-l+1;
if(sum[r]-sum[l-1]==len*(len+1)/2&&ans<l) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: