Link do tópico: clique para visualizar
A ideia principal da pergunta: dada uma sequência numérica de comprimento n, o intervalo de valores de cada número é [1, m], e a pergunta garante que cada número apareça pelo menos uma vez. Agora, para i ∈ [1, m], saída no original Na sequência, o menor comprimento de todos os tipos de números, incluindo [1, i]
Análise do problema: pensei em muitos métodos quando comecei, mas eles não puderam otimizar a complexidade do tempo por meio da estrutura de dados, como O (m) enumerando números, toda vez que O (n) vai para a régua, ou O (m) ) Enumere os números e dobre o comprimento para verificar; quanto mais você pensa, mais ridículo. .
Na verdade, este tópico já pensou sobre a necessidade de recursivamente, primeiro colocar a solução oficial do problema:
Para simplificar, quando o intervalo de números que precisa ser incluído é determinado [1, i], enumere cada posição como o ponto final esquerdo ou direito, e o outro ponto final correspondente deve ser encontrado, então podemos também enumerar este tópico Endpoint esquerdo, então vá para determinar o endpoint direito
Seja R [i] [l] os seguintes significados: o intervalo atual de números que precisam ser incluídos é [1, i], com o ponto l como ponto final esquerdo, o valor mínimo do ponto final direito
Então, obviamente, para cada i, a resposta é min (R [i] [1], R [i] [2], ..., R [i] [n])
A solução oficial explicou em detalhes como manter o array R com a árvore do segmento de linha. A única coisa que não está clara é como manter a resposta, ou seja, R [i] [l] -l + 1
Nesta questão, você precisa usar a modificação de intervalo da árvore de segmento de linha, ou seja, você precisa modificar uniformemente o valor de um determinado intervalo para outro valor, então para um nó na árvore de segmento de linha, suponha que seu intervalo de manutenção seja [l, r] , Se o valor do intervalo for modificado uniformemente para x, então as respostas no intervalo se tornam {x-l + 1, x- (l + 1) + 1, ..., x-r + 1}, observe Não é difícil encontrar os valores de r-l + 1. Cada item de x + 1 existe. A única diferença é a subtração. Como precisamos do valor mínimo, a subtração é obviamente a melhor quando tomamos o ponto final correto. Sim, atualize a resposta deste nó para ans [k] = x-r + 1
Código:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=2e5+100;
vector<int>pos[N];
struct Node
{
int l,r;
int lazy,ans,mmin;
}tree[N<<2];
void pushup(int k)
{
tree[k].ans=min(tree[k<<1].ans,tree[k<<1|1].ans);
tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);
}
void pushdown(int k)
{
if(tree[k].lazy)
{
int lz=tree[k].lazy;
tree[k].lazy=0;
tree[k<<1].lazy=tree[k<<1|1].lazy=lz;
tree[k<<1].mmin=tree[k<<1|1].mmin=lz;
tree[k<<1].ans=lz-tree[k<<1].r+1;
tree[k<<1|1].ans=lz-tree[k<<1|1].r+1;
}
}
void build(int k,int l,int r)
{
tree[k].l=l;
tree[k].r=r;
tree[k].ans=inf;
tree[k].mmin=tree[k].lazy=0;
if(l==r)
return;
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void update(int k,int l,int r,int val)
{
if(l>r)
return;
if(tree[k].r<l||tree[k].l>r)
return;
if(tree[k].l>=l&&tree[k].r<=r)
{
tree[k].mmin=tree[k].lazy=val;
tree[k].ans=val-tree[k].r+1;
return;
}
pushdown(k);
update(k<<1,l,r,val);
update(k<<1|1,l,r,val);
pushup(k);
}
int query(int k,int l,int r,int x)//询问[l,r]内小于x的最大位置
{
if(tree[k].r<l||tree[k].l>r)
return -1;
if(tree[k].mmin>=x)
return -1;
if(tree[k].l==tree[k].r)
return tree[k].l;
pushdown(k);
int mid=tree[k].l+tree[k].r>>1;
int pos=query(k<<1|1,l,r,x);
if(pos==-1)
pos=query(k<<1,l,r,x);
return pos;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int num;
scanf("%d",&num);
pos[num].push_back(i);
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
int pre=1;
for(auto p:pos[i])
{
int pos=query(1,pre,p,p);
update(1,pre,pos,p);
pre=p+1;
}
update(1,pos[i].back()+1,n,inf);
printf("%d%c",tree[1].ans,i==m?'\n':' ');
}
return 0;
}