2020 ICPC (Xiaomi Invitational 1) -Red de teléfono (recursividad de optimización de árbol de segmento de línea)

Enlace de tema: haga clic para ver

La idea principal de la pregunta: dada una secuencia numérica de longitud n, el rango de valores de cada número es [1, m], y la pregunta garantiza que cada número aparece al menos una vez. Ahora, para i ∈ [1, m], la salida es el original En la secuencia, la longitud más corta de todos los tipos de números, incluido [1, i]

Análisis de problemas: pensé en muchos métodos cuando comencé, pero no podían optimizar la complejidad del tiempo a través de la estructura de datos, como O (m) enumerando números, cada vez que O (n) va a la regla, o O (m ) Enumere los números y luego verifique la longitud de la bisección. Cuanto más piensa, más indignante es. .

De hecho, este tema ya ha pensado en la necesidad de, de forma recursiva, poner primero la solución oficial del problema:

En pocas palabras, cuando se determina el rango de números que deben incluirse [1, i], luego enumere cada posición como un extremo izquierdo o derecho, y se debe encontrar el correspondiente, por lo que también podríamos enumerar para este tema Punto final izquierdo, luego vaya a determinar el punto final derecho

Deje que R [i] [l] tenga los siguientes significados: el rango actual de números que deben incluirse es [1, i], con el punto l como el punto final izquierdo, el valor mínimo del punto final derecho

Entonces, obviamente, para cada i, la respuesta es min (R [i] [1], R [i] [2], ..., R [i] [n])

La solución oficial del problema ha explicado en detalle cómo usar el árbol de segmento de línea para mantener la matriz R. Lo único que no está claro es cómo mantener la respuesta, que es R [i] [l] -l + 1

En esta pregunta, debe usar la modificación de intervalo del árbol de segmento de línea, es decir, debe modificar uniformemente el valor de un cierto intervalo a otro valor, luego, para un nodo en el árbol de segmento de línea, suponga que su intervalo de mantenimiento es [l, r] , Si el valor del intervalo se modifica uniformemente ax, entonces las respuestas en el intervalo se vuelven secuencialmente {x-l + 1, x- (l + 1) + 1, ..., x-r + 1}, observe No es difícil encontrar los valores r-l + 1. Cada elemento de x + 1 existe. La única diferencia es la resta. Debido a que necesitamos el valor mínimo, la resta es obviamente la mejor cuando tomamos el punto final correcto. Sí, actualice la respuesta de este nodo a 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;
}

 

Supongo que te gusta

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