hdu 5919 Sequence II 2016ACM/CCPC长春赛区现场赛J

Problem Description
Mr. Frog has an integer sequence of length n, which can be denoted as  a1,a2,,an  There are m queries.

In the i-th query, you are given two integers  li  and  ri . Consider the subsequence  ali,ali+1,ali+2,,ari .

We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as  p(i)1,p(i)2,,p(i)ki  (in ascending order, i.e., p(i)1<p(i)2<<p(i)ki ).

Note that  ki  is the number of different integers in this subsequence. You should output  p(i)ki2 for the i-th query.
 

Input
In the first line of input, there is an integer T ( T2 ) denoting the number of test cases.

Each test case starts with two integers n ( n2×105 ) and m ( m2×105 ). There are n integers in the next line, which indicate the integers in the sequence(i.e.,  a1,a2,,an,0ai2×105 ).

There are two integers  li  and  ri  in the following m lines.

However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to  li,ri(1lin,1rin) . As a result, the problem became more exciting.

We can denote the answers as  ans1,ans2,,ansm . Note that for each test case  ans0=0 .

You can get the correct input  li,ri  from what you read (we denote them as  li,ri )by the following formula:
li=min{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}

ri=max{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}
 

Output
You should output one single line for each test case.

For each test case, output one line “Case #x:  p1,p2,,pm ”, where x is the case number (starting from 1) and  p1,p2,,pm  is the answer.
 

Sample Input
  
  
2 5 2 3 3 1 5 4 2 2 4 4 5 2 2 5 2 1 2 2 3 2 4
 

Sample Output
  
  
Case #1: 3 3 Case #2: 3 1
Hint


先写了一个二分位置两个log的。。然后T了。听说现场赛可以过

然后去看了题解,发现只要倒着枚举l加入,每次只将离l最近的第一次出现的各个不同数的位置+1

这样如果询问l,r,那么就直接询问区间和就可以了

然后求k/2。因为倒着加入的,所以可以直接在线段树直接查询值为k/2的那个位置就好,这样就不需要二分那个log了

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
struct tree
{
	//int l,r;
	int ll,rr;
	int s;
}tr[10000001];
int tot;
int rt[2000001],a[2000001];
int n;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9')
	{
	//if(ch=='-')f=-1;
	ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void build(int l,int r)
{
	int p=tot;
	//tr[p].l=l;
	//tr[p].r=r;
	if(l!=r)
	{
		int mid=(l+r)/2;
		tot++;
		tr[p].ll=tot;
		build(l,mid);
		tot++;
		tr[p].rr=tot;
		build(mid+1,r);
		tr[p].s=tr[tr[p].ll].s+tr[tr[p].rr].s; 
	}
	else
	{
		tr[p].ll=0;
		tr[p].rr=0;
		tr[p].s=0;
	}
}
inline int inc(int p,int ll,int rr,int l,int r,int x)
{
	if(p==0)
		return 0;
	if(ll==l&&rr==r)
	{
		tot++;
	//	tr[tot].l=l;
	//	tr[tot].r=r;
		tr[tot].s=tr[p].s+x;
		return tot;
	}
	else
	{
		int mid=(ll+rr)/2;
		tot++;
		int pp=tot;
		//tr[pp].l=tr[p].l;
	//	tr[pp].r=tr[p].r;
		if(l<=mid)
			tr[pp].ll=inc(tr[p].ll,ll,mid,l,r,x);
		else
			tr[pp].ll=tr[p].ll;
		if(r>mid)
			tr[pp].rr=inc(tr[p].rr,mid+1,rr,l,r,x);
		else
			tr[pp].rr=tr[p].rr;
		tr[pp].s=tr[tr[pp].ll].s+tr[tr[pp].rr].s;
		return pp;
	}
}
inline int ask(int p2,int p1,int ll,int rr,int l,int r)
{
	if(p1==0)
		return 0;
	if(l<=ll&&rr<=r)
		return tr[p2].s-tr[p1].s;
	else
	{
		int mid=(ll+rr)/2;
		int sum=0;
		if(l<=mid)
			sum+=ask(tr[p2].ll,tr[p1].ll,ll,mid,l,r);
		if(r>mid)
			sum+=ask(tr[p2].rr,tr[p1].rr,mid+1,rr,l,r);
		return sum;
	}
}
inline int sx(int p,int l,int r,int x)
{
	if(l==r)
		return l;
	int mid=(l+r)/2;
	if(tr[tr[p].ll].s>=x)
		return sx(tr[p].ll,l,mid,x);
	return sx(tr[p].rr,mid+1,r,x-tr[tr[p].ll].s);
}
int la[2000001];
int main()
{
	int T,k=0;
	//scanf("%d",&T);
	T=read();
	while(T>0)
	{
		T--;
		k++;
		int m;
		n=read();
		m=read();
	//	scanf("%d%d",&n,&m);
		int i;
		for(i=1;i<=n;i++)
			a[i]=read();
		//	scanf("%d",&a[i]);
		memset(la,0,sizeof(la));
		tot=1;
		rt[0]=1;
		build(1,n);
		for(i=n;i>=1;i--)
		{
			if(la[a[i]]==0)
			{
				rt[i]=tot+1;
				inc(rt[(i+1)%(n+1)],1,n,i,i,1);
				la[a[i]]=i;
			}
			else
			{
				int d=tot+1;
				inc(rt[(i+1)%(n+1)],1,n,la[a[i]],la[a[i]],-1);
				rt[i]=tot+1;
				inc(d,1,n,i,i,1);
				la[a[i]]=i;
			}
		}
		printf("Case #%d:",k);
		int lx,rx,l,r;
		int las=0;
		for(i=1;i<=m;i++)
		{
		//	scanf("%d%d",&lx,&rx);
			lx=read();
			rx=read();
			l=min((lx+las)%n+1,(rx+las)%n+1);
			r=max((lx+las)%n+1,(rx+las)%n+1);
			//printf("\n\n%d %d\n\n",l,r);
			int sum=ask(rt[l],rt[(r+1)%(n+1)],1,n,l,r);
			int dx=(sum+1)/2;
			int ll=sx(rt[l],1,n,dx);
			printf(" %d",ll);
			las=ll;
		}
		printf("\n"); 
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值