您的位置:首页 > 其它

HDU 5172 GTY's gay friends 线段树(排列,区间不同的数)

2017-10-10 14:03 447 查看
HDU 5172

题意:给出长度为n的序列a,m次询问[L,R],问a[L]..a[R]是不是[1..R-L+1]的某个排列?.

n,m<=1e5,a[i]<=n.

m=R-L+1,若[L,R]的区间和为sum=m*(1+m)/2 并且[L,R]每个数都不相同 则说明[L,R]为1..m的一个排列.

因为[L,R]每个数都不同 设最小为mn 则要想和为sum 则mn=1 并且排序后每个数都相差1.

没有修改操作,用前缀和来解决区间的和,

判断该[L,R]区间内每个数都不同? last[i]为a[i]上一次出现的位置.

将last[i]插入线段树中 若[ql,qr]内的last最大值<ql 则说明[ql,qr]每个数都不同.

当然也可以离线

将查询的区间按照右端点排序,同时记录每一个数上一次出现的位置.
只在线段树中保留x最后一次出现的位置,对询问区间求一次和即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+2;
struct Node{
int l,r,mx;
}t[N*4];
int n,Q,last
,now
;
int a
;
ll pre
;
void push_up(int o)
{
t[o].mx=max(t[o<<1].mx,t[o<<1|1].mx);
}
void build(int o,int l,int r)
{
t[o].l=l,t[o].r=r;
if(l==r)
{
t[o].mx=last[l];
return;
}
int m=l+r>>1;
build(o<<1,l,m);
build(o<<1|1,m+1,r);
push_up(o);
}
int query(int o,int ql,int qr)
{
int l=t[o].l,r=t[o].r,m=l+r>>1;
if(ql<=l&&qr>=r)
return t[o].mx;
int res=0;
if(ql<=m)
res=max(res,query(o<<1,ql,qr));
if(qr>m)
res=max(res,query(o<<1|1,ql,qr));
return res;
}
int main()
{
while(scanf("%d%d",&n,&Q)!=EOF)
{

pre[0]=0;
memset(now,0,sizeof(now));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
last[i]=now[a[i]];
now[a[i]]=i;
pre[i]=pre[i-1]+a[i];
}
build(1,1,n);
for(int i=1;i<=Q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
ll m=r-l+1;
ll sum=(1+m)*m/2;
if(pre[r]-pre[l-1]!=sum)
{
printf("NO\n");
continue;
}
if(query(1,l,r)<l)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: