J - Different Integers(树状数组)

Given a sequence of integers a1,a2,⋯,an and q pairs of integers (l1,r1),(l2,r2),⋯,(lq,rq), find count(l1,r1), count(l2,r2), ⋯, count(lq,rq) where count(i,j) is the number of different integers among a1,a2,⋯,ai,aj,aj+1,⋯,an.

Input
The input consists of several test cases and is terminated by end-of-file.

The first line of each test cases contains two integers n and q.

The second line contains n integers a1,a2,⋯,an.

The i-th of the following q lines contains two integers li and ri.

  • 1≤n,q≤105
  • 1≤ai≤n
  • 1≤li,ri≤n
  • The number of test cases does not exceed 10.

Output
For each test case, print q integers which denote the result.

Example
Input
3 2
1 2 1
1 2
1 3
4 1
1 2 3 4
1 3
Output
2
1
3
很容易地想到环,然后就是进行拼接来方便处理:a1 a2 … an a1 a2 … an
这样原本的区间a1 a2 … al ar ar+1 … an 就变成了 ar ar+1 … al 即【r,n+l】
用1来标记区间内的那个数是不是第一次出现,这样题目就转换成了求区间的和,也就是用树状数组进行区间求和
树状数组详解

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
    
    
	int l,r,sx;//输入顺序 
}fin[100100];
int a[200200],first[200200],nextn[200200],resite[100100],c[200200],result[100100]; 
int lowbit(int x)//2^k
{
    
    
	return x&-x;
}
void update(int x,int val)//更新
{
    
    
 while(x<200200)
 {
    
    
   c[x]+=val;
   x+=lowbit(x);	
 }	
} 
int sum(int x)//求数组1-x的和 
{
    
    
	int s=0;
	while(x)
	{
    
    
	  s+=c[x];
	  x-=lowbit(x);	
	} 
	return s;
}
int cmp(node x,node y)
{
    
    
	return x.l<y.l;
}
int main()
{
    
      
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
    
    
		memset(nextn, 0, sizeof(nextn));
		memset(resite, 0, sizeof(resite));
		memset(c, 0, sizeof(c)); 
		for(int i=1;i<=n;i++)
		{
    
    
			scanf("%d",&a[i]);
			a[n+i]=a[i];//拼接在一起,方便算
			first[i]=1;first[n+i]=1;// first数组储存i位置上的数是否是第一次出现,在此处初始化为1
		}
		for(int  i=2*n;i>=1;i--)
		{
    
    
			nextn[i]=resite[a[i]];//储存i位置上的数的下一个出现的位置
			first[resite[a[i]]]=0;//数a[i]后面已经出现过了,不是第一次出现的,那个位置置0 
			resite[a[i]]=i;//resite储存a[i]数从后往前最近出现的位置 
		}
		for(int i=1;i<=2*n;i++)
		 if(first[i])
		  update(i,1);//维护first的树状数组
		 
		for(int i=1;i<=q;i++)
		{
    
    
		 scanf("%d%d",&fin[i].l,&fin[i].r);
		 fin[i].sx=i;
		 fin[i].l+=n;
		 swap(fin[i].l,fin[i].r);//拼接 
		} 
		sort(fin+1,fin+q+1,cmp);
		for(int i=1,j=1;i<=2*n&&j<=q;)
		{
    
    
			if(i==fin[j].l)//开头判断 
			{
    
    
				result[fin[j].sx]=sum(fin[j].r)-sum(fin[j].l)+1;
				j++; 
			}
			else
			{
    
    
				if(first[i])//第一次出现的标记往后移,更新数组 
				{
    
    
					first[i]=0; first[nextn[i]]=1;
					update(i,-1);
					update(nextn[i],1);
				}
				i++;
			}
		}
		for(int i=1;i<=q;i++)
		 printf("%d\n",result[i]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43540515/article/details/113069348