您的位置:首页 > 产品设计 > UI/UE

hdu5919 Sequence II(主席树,区间第k大)

2016-10-08 16:15 351 查看

hdu5919

题目

给你n个数字,和m个查询.将[l,r]之间数第一次出现的位置信息弄成一个新的数组,然后找出其中k/2大的数.(k为位置的数量)

思路

主席树,倒着插入可以保证存的是数字第一次出现的位置。强行学习了一波。(借鉴别人的代码)

代码

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int N=2e5+5;
const int M=40*N;
int T
,po
,a
;
struct Seg
{
int ls,rs,v;
} tr[M];
int tot,C,n,m;

int build(int l,int r)
{
int rt=++tot;
tr[rt].v=0;
if(l==r)
{
tr[rt].ls=tr[rt].rs=0;
return rt;
}
int m=(l+r)>>1;
tr[rt].ls=build(l,m);
tr[rt].rs=build(m+1,r);
return rt;
}

int update(int rt,int l,int r,int pos,int d)
{
int newrt=tot++;
tr[newrt].v=tr[rt].v+d;
if(l==r) return newrt;
int m=(l+r)>>1;
if(pos<=m)
{
tr[newrt].rs=tr[rt].rs;
tr[newrt].ls=update(tr[rt].ls,l,m,pos,d);
}
else
{
tr[newrt].ls=tr[rt].ls;
tr[newrt].rs=update(tr[rt].rs,m+1,r,pos,d);
}
return newrt;
}

int getsum(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tr[rt].v;
int m=(l+r)>>1;
int res=0;
if(L<=m) res+=getsum(tr[rt].ls,l,m,L,R);
if(m<R) res+=getsum(tr[rt].rs,m+1,r,L,R);
return res;
}

int query(int rt,int l,int r,int k)
{
if(l==r) return l;
int m=(l+r)>>1;
int tmp=tr[tr[rt].ls].v;
if(k<=tmp) return query(tr[rt].ls,l,m,k);
else return query(tr[rt].rs,m+1,r,k-tmp);
}

int main()
{
int t,kase=1;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
tot=0;
T[n+1]=build(1,n);
memset(po,-1,sizeof(po));
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
for(int i=n; i>=1; i--)
{
if(po[a[i]]==-1)
{
T[i]=update(T[i+1],1,n,i,1);
}
else
{
int tmp=update(T[i+1],1,n,po[a[i]],-1);
T[i]=update(tmp,1,n,i,1);
}
po[a[i]]=i;
}
printf("Case #%d:",kase++);
int ans=0;
while (m--)
{
int p,q,l,r;
scanf("%d %d",&p,&q);
p=(p+ans)%n+1;
q=(q+ans)%n+1;
l=min(p,q);
r=max(p,q);
int k=getsum(T[l],1,n,l,r);
ans=query(T[l],1,n,(k+1)/2);
printf(" %d",ans);
}
puts("");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: