2020 ICPC (Xiaomi Invitational 1) -Rede de telefone (recursão de otimização de árvore de segmento de linha)

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

 

Acho que você gosta

Origin blog.csdn.net/qq_45458915/article/details/109311760
Recomendado
Clasificación