[HDU 5919]Sequence II

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5919
大意
给定一个长为 n n n的数组 a [ ] a[] a[],要处理 q q q个询问,每个询问给出一个区间 [ l , r ] [l,r] [l,r],设该区间内共出现了 k k k个不同的数,第 i i i个数出现的位置为 p i p_i pi(显然 p 1 &lt; p 2 &lt; … … &lt; p k p_1&lt;p_2&lt;……&lt;p_k p1<p2<<pk),输出 p ⌈ k / 2 ⌉ p_{⌈k/2⌉} pk/2
思路
用主席树,如果将 a [ ] a[] a[] a n 、 a n − 1 … … a 1 a_n、a_{n-1}……a_1 anan1a1的次序插入,插入 a i a_i ai时在当前位置+1,并且若 a i a_i ai不是第一次出现,则在 a i a_i ai上一次出现的位置-1,那么我们就可以在当前的主席树(设为第 i i i棵主席树)上查询 [ i , j ] [i,j] [i,j] i &lt; = j &lt; = n i&lt;=j&lt;=n i<=j<=n)出现的数字数量 k k k了,然后只要同样在当前的主席树上查找位置最小的满足出现数量不小于 ⌈ k / 2 ⌉ ⌈k/2⌉ k/2的位置即可。
查询位置时若左边已存在的数字数量大于或等于目标则直接查询左边,否则查询右边,可以保证时间复杂度是O( l o g log log n n n)
因为我是反向插入所以在满足条件时是优先查询右边

int getans(int root,int l,int r,int tz,int l_,int r_)
{
	if(l==r)return l;
	int mid=(l_+r_)/2;
	if(l>mid)return getans(tree[root].rson,l,r,tz,mid+1,r_);
	else if(r<=mid)return getans(tree[root].lson,l,r,tz,l_,mid);
	else
	{
		if(tree[tree[root].rson].sum>=tz)return getans(tree[root].rson,mid+1,r,tz,mid+1,r_);
		else return getans(tree[root].lson,l,mid,tz-tree[tree[root].rson].sum,l_,mid);
	}
}

AC代码

#include<stdio.h>
#include<map>
#include<queue>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#define MOD 10000000007
#define N 200005
typedef long long LL;
using namespace std;
typedef struct node{
	int lson,rson,sum;
}node;
LL tot,n,m,te,len,s,t,k,l,r,l_,r_,ans;
int a[N];
node tree[N*40];
int R[N];
int last[N];
int answer[N];
void init()
{
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[n-i+1]);
	}
}
void insert(int pre,int &root,int l,int r,int val,int l_,int r_)
{
	tree[++tot]=tree[pre];root=tot;
	tree[root].sum+=val;
	if(l_==l&&r_==r) 
	{
		return;
	}
	int mid=(l_+r_)/2;
	if(l>mid) insert(tree[root].rson,tree[root].rson,l,r,val,mid+1,r_);
	else if(r<=mid)insert(tree[root].lson,tree[root].lson,l,r,val,l_,mid);
	return;
}
int query(int root,int l,int r,int l_,int r_)
{
	if(l_==l&&r_==r)return tree[root].sum;
	int mid=(l_+r_)/2;
	if(l>mid)return query(tree[root].rson,l,r,mid+1,r_);
	else return query(tree[root].lson,l,mid,l_,mid)+tree[tree[root].rson].sum;
}
int getans(int root,int l,int r,int tz,int l_,int r_)
{
	if(l==r)return l;
	int mid=(l_+r_)/2;
	if(l>mid)return getans(tree[root].rson,l,r,tz,mid+1,r_);
	else if(r<=mid)return getans(tree[root].lson,l,r,tz,l_,mid);
	else
	{
		if(tree[tree[root].rson].sum>=tz)return getans(tree[root].rson,mid+1,r,tz,mid+1,r_);
		else return getans(tree[root].lson,l,mid,tz-tree[tree[root].rson].sum,l_,mid);
	}
}
int main()
{
	scanf("%d",&t);int ct=0;
	while(t--)
	{
		ct++;
		scanf("%d%d",&n,&m);
		init();
		tot=0;
		R[0]=0;tree[0].lson=tree[0].rson=tree[0].sum=0;
		for(int i=1;i<=n;i++)
		{
			if(last[a[i]])
			{
				insert(R[i-1],R[i],last[a[i]],last[a[i]],-1,1,n);
				insert(R[i],R[i],i,i,1,1,n);
			}else
			{
				insert(R[i-1],R[i],i,i,1,1,n);
			}
			last[a[i]]=i;
		}
		ans=0;
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d",&l_,&r_);
			l=min((l_+ans)%n+1,(r_+ans)%n+1);r=max((l_+ans)%n+1,(r_+ans)%n+1);
			k=query(R[n-l+1],n-r+1,n,1,n);
			ans=getans(R[n-l+1],n-r+1,n-l+1,(k+1)/2,1,n);
			ans=n-ans+1;
			answer[i]=ans;
		}
		for(int i=1;i<=n;i++)last[a[i]]=0;
		printf("Case #%d:",ct);
		for(int i=1;i<=m;i++)printf(" %d",answer[i]);
		printf("\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值