HDU - 5919(主席树)

题解:我们可以倒序插入,然后我们查询的时候查询区间有多少个不同的数,接着查询之后假设有k个不同的数,接着我们可以根据区间有多少不同的数然后查询第(k+1)/2个数的第一个位置,加入我主席树左子树大于等于(k+1)/2个不同的数那么第一个位置肯定在左子树,否则在右子树,我们到最后L==R那么肯定是位置在L了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int mx = 2e5+5;
#define mid (L+R)/2
struct node{
	int ls,rs;
	int sum;
}T[50*mx];
int sz;
int root[mx];
void built(int &rt,int L,int R){
	rt = sz++;
	T[sz].sum = 0;
	if(L==R)
		return;
	built(T[sz].ls,L,mid);
	built(T[sz].rs,mid+1,R);
}
void creat(int &rt,int x,int L,int R,int p,int v){
	rt = sz++;
	T[rt] = T[x];
	T[rt].sum+=v;
	if(L==R)
		return;
	if(p<=mid)	creat(T[rt].ls,T[x].ls,L,mid,p,v);
	else		creat(T[rt].rs,T[x].rs,mid+1,R,p,v);
}
int query(int end,int rt,int L,int R){
	if(R<=end)	
		return T[rt].sum;
	if(mid<end)	return T[T[rt].ls].sum+query(end,T[rt].rs,mid+1,R);
	else return query(end,T[rt].ls,L,mid);
}
int Query(int end,int rt,int L,int R,int k){
	if(L==R)
		return L;
	int s = T[T[rt].ls].sum;
	if(s<k)	return Query(end,T[rt].rs,mid+1,R,k-s);
	else return Query(end,T[rt].ls,L,mid,k);
}
map<int,int>mp;
int ans[mx];
int a[mx];
int main(){	
	int t;
	scanf("%d",&t);
	int ca = 1;
	int n,m;
	while(t--){
		scanf("%d%d",&n,&m);
		sz = 0; 
		int tmp;
		built(root[n+1],1,n);
		mp.clear();
		for(int i = 1; i <= n; i++)
			scanf("%d",&a[i]);
		for(int i = n; i >= 1; i--)
			if(!mp[a[i]]){
				creat(root[i],root[i+1],1,n,i,1);
				mp[a[i]] = i;
			}
			else{
				creat(tmp,root[i+1],1,n,mp[a[i]],-1);
				creat(root[i],tmp,1,n,i,1);
				mp[a[i]] = i;
			}
		printf("Case #%d: ",ca++);
		for(int j = 1; j <= m; j++){
			int l,r;
			scanf("%d%d",&l,&r);
			l = (l+ans[j-1])%n+1;
			r = (r+ans[j-1])%n+1;
		//	cout<<l<<r<<endl;
			if(l>r)
				swap(l,r);
			int k = query(r,root[l],1,n);
		//	cout<<k<<endl;
			k = Query(r,root[l],1,n,(k+1)/2);
			ans[j] = k;
			printf("%d%c",k,j==m?'\n':' ');
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1325136367/article/details/79747199