J-Different Integers (tree array)

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
It is easy to think of the loop, and then it is spliced ​​to facilitate processing: a1 a2… an a1 a2… an
original interval a1 like this a2… al ar ar+1… an becomes ar ar+1… al that is [r,n+l]
Use 1 to mark whether the number in the interval appears for the first time, so that the question is transformed into seeking The sum of intervals, that is, the interval summation of the tree array is used for
detailed explanation of the tree array

#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;
}

Guess you like

Origin blog.csdn.net/weixin_43540515/article/details/113069348