J-Diferentes enteros (matriz de árbol)

Dada una secuencia de enteros a1, a2, ⋯, an y q pares de enteros (l1, r1), (l2, r2), ⋯, (lq, rq), encuentre count (l1, r1), count (l2, r2 ), ⋯, count (lq, rq) donde count (i, j) es el número de enteros diferentes entre a1, a2, ⋯, ai, aj, aj + 1, ⋯, an.

Entrada
La entrada consta de varios casos de prueba y finaliza al final del archivo.

La primera línea de cada caso de prueba contiene dos números enteros n y q.

La segunda línea contiene n números enteros a1, a2, ⋯, an.

La i-ésima de las siguientes q líneas contiene dos enteros li y ri.

  • 1≤n, q≤105
  • 1≤ai≤n
  • 1≤li, ri≤n
  • El número de casos de prueba no supera los 10.

Salida
Para cada caso de prueba, imprima q enteros que denotan el resultado.

Ejemplo
Entrada
3 2
1 2 1
1 2
1 3
4 1
1 2 3 4
1 3
Salida
2
1
3
Es fácil pensar en el lazo, y luego se empalma para facilitar el procesamiento: a1 a2… an a1 a2… un
intervalo original a1 como este a2… al ar ar + 1… an se convierte en ar ar + 1… al que es [r, n + l]
Use 1 para marcar si el número en el intervalo aparece por primera vez, de modo que el la pregunta se transforma en búsqueda La suma de intervalos, es decir, la suma de intervalos de la matriz de árbol se utiliza para
una explicación detallada de la matriz de árbol

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

Supongo que te gusta

Origin blog.csdn.net/weixin_43540515/article/details/113069348
Recomendado
Clasificación