【HDU5919】SequenceII(主席树)

【HDU5919】SequenceII(主席树)

题面

Vjudge
翻译(by ppl)

给一个长度为N的数列A,有m个询问,每次问
数列[l,r]区间中所有数的第一次出现的位置的中位
数是多少

题解

先考虑一下怎么求区间内有多少个不同的数
方法有两种

第一种:
记录一下每个数上一次出现的位置
每次将这个位置+1
最后求\(l,r\)区间内的数的个数
也就是求区间内上一次出现的位置在\(l\)左侧的数的个数
直接查询区间和即可

第二种:
将序列到过来插入
每次记录这个数上一次出现的位置(倒过来的!!!)
然后将上一次出现的位置-1
这一次出现的位置+1
每次询问\(l,r\)
直接查询第\(l\)棵主席树中\(l,r\)的区间和即可

这道题目既然要求所有的第一次出现的数的位置的中位数
显然要维护位置信息,所以考虑第二种方法,
第一种维护的是上一次出现位置的信息

查询一下区间内有多少个数,然后求区间第\(K\)大的位置即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 222222
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int tot,rt[MAX];
struct Node
{
	int ls,rs;
	int v;
}t[MAX<<5];
void Modify(int &x,int ff,int l,int r,int p,int w)
{
	t[x=++tot]=t[ff];t[x].v+=w;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(p<=mid)Modify(t[x].ls,t[ff].ls,l,mid,p,w);
	else Modify(t[x].rs,t[ff].rs,mid+1,r,p,w);
}
int Query(int r1,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)return t[r1].v;
	int mid=(l+r)>>1,ret=0;
	if(L<=mid)ret+=Query(t[r1].ls,l,mid,L,R);
	if(R>mid)ret+=Query(t[r1].rs,mid+1,r,L,R);
	return ret;
}
int Kth(int r1,int l,int r,int K)
{
	if(l==r)return l;
	int mid=(l+r)>>1,s=t[t[r1].ls].v;
	if(s>=K)return Kth(t[r1].ls,l,mid,K);
	else return Kth(t[r1].rs,mid+1,r,K-s);
}
int ans,n,a[MAX],m;
int lst[MAX],pos[MAX];
int main()
{
	int T=read();
	for(int TTT=1;TTT<=T;++TTT)
	{
		printf("Case #%d:",TTT);
		memset(rt,0,sizeof(rt));
		memset(t,0,sizeof(t));
		memset(lst,0,sizeof(lst));
		memset(pos,0,sizeof(pos));
		tot=ans=0;
		n=read();m=read();
		for(int i=1;i<=n;++i)a[i]=read();
		for(int i=n;i;--i)
			if(!pos[a[i]])Modify(rt[i],rt[i+1],1,n,i,1),pos[a[i]]=i;
			else
			{
				Modify(rt[i],rt[i+1],1,n,i,1);
				Modify(rt[i],rt[i],1,n,pos[a[i]],-1);
				pos[a[i]]=i;
			}
		while(m--)
		{
			int L=(read()+ans)%n+1,R=(read()+ans)%n+1;
			if(L>R)swap(L,R);
			int S=Query(rt[L],1,n,L,R);
			ans=Kth(rt[L],1,n,(S+1)/2);
			printf(" %d",ans);
		}
		puts("");
	}
	return 0;
}

posted @ 2018-04-02 16:10  小蒟蒻yyb  阅读(785)  评论(0编辑  收藏  举报