Solución CF1039D

Enlace del título

Asunto

Dado un árbol con \ (n \) nodos, para cada número entre \ (1 \) ~ \ (n \) \ (k \) , debe preguntar: cuántos elementos se pueden seleccionar como máximo La longitud de cada ruta de intersección es \ (k \) .

\(Solución:\)

\ (1 \) ~ \ (n \) no es fácil de contar, primero considere un solo \ (k \) .
Deje que \ (ans_i \) indique la cantidad máxima de rutas mutuamente disjuntas que se pueden seleccionar. La longitud de cada ruta es \ (i \) . \ (F_u \) indica que la cantidad máxima de rutas se puede seleccionar cuando se retrocede a \ (u \) Cuántas rutas no se cruzan entre sí, la longitud de cada ruta es \ (i \) ( \ (i \) es la anterior \ (i \) );

Considere codiciosos \ (DP \) : Para un punto \ (T \) , consideramos que para maximizar el \ (T \) es el subárbol con raíz en toda la longitud de \ (K \) ruta número de , en segundo lugar más grande La longitud de la cadena inacabada ; la
corrección es obviamente: debido a la naturaleza del árbol, el nodo \ (u \) solo se contará en una ruta, luego usamos un punto de vista similar para dividir y conquistar, sea \ (u \) el \ (Dep \) es el punto más superficial de la ruta , \ (max1 \) es la longitud de la cadena más larga que cuelga del nodo \ (u \) , \ (max2 \) está \ (u \) que cuelga La longitud de la segunda cadena más larga, entonces:
\ ((1) \) Si \ (max1 + max2 + 1 \ geq k \) , entonces obviamente queremos incluir la ruta compuesta de \ (max1, max2, u \) en la respuesta , De lo contrario, se usará el nodo ancestro de \ (u \) , que no es óptimo;
\ ((2) De lo contrario \) , usaremos la cadena de \ (max1, u \) para heredar

Código probablemente se parece a esto (leer \ (lzy \) Gangster \ (Blog \) , descubrió que, de hecho, por primera vez puede \ (DFS \) de nuevo corrió \ (DFS \) secuencia, y luego directamente en los \ (DFS \) Operar en secuencia, nuevas habilidades \ (get \) )

void dfs(int u,int fa)
{
	fat[u]=fa;
	go(u)
	{
		int v=e[i].to;
		if(v!=fa) dfs(v,u);
	}
	dfn[++idx]=u;
} 
inline int solve(int k)
{
	int ans=0;
	fr(i,1,n) f[i]=1;
	fr(i,1,n)
	{
		int u=dfn[i];
		if(fat[u]&&f[fat[u]]&&f[u])
		{
			if(f[u]+f[fat[u]]>=k)
			{
				++ans,f[fat[u]]=0;
			}
			else f[fat[u]]=max(f[fat[u]],f[u]+1);
		}
	}
	return ans;
}

Sin embargo, esto es \ (O (n ^ 2) \) , considere la optimización. Se puede encontrar que: \ (ans_i \ leq \ frac {n} {i} \) (la razón es que la longitud de la ruta es \ (i \) , entonces el mejor caso es usar todos los puntos, habrá \ (\ frac { n} {i} \) rutas).

Luego, combinado con el rango de datos \ (n \ leq 10 ^ 5 \) , podemos dividir y conquistar con el signo raíz: para un determinado \ (k \) , establecemos un umbral \ (B \) :
\ ((1) \) If \ (k \ leq B \) , violencia directa \ (dp \) (es decir, el código anterior), complejidad \ (O (nB) \) ;
\ ((2) \) If \ (k> B \) , debe haber: \ (ans_k \ in [0, \ frac {n} {B}] \) , es decir, solo \ (\ frac {n} {B} \) tiene tantos valores , Entonces \ (f \) (es decir, \ (dp \) array) obviamente tiene una naturaleza monótona y no creciente , es decir , el valor dp de un segmento en el medio es el mismo , entonces consideramos dicotomizar los límites de estos segmentos, cada dicotomía utilizado solve()para \ (Check \) , la complejidad de la \ (O (\ {n-FRAC} {B} n- \ n-log_2) \) .

Luego analizamos ahora el valor del umbral \ (B \) . Del análisis anterior, podemos ver que la complejidad total \ (O (nB + \ frac {n} {B} n \ log_2 n) = O (n (B + \ frac {n} {B} \ log n)) \) , por la desigualdad media: \ (min = n \ sqrt {n \ log n} \) , si y solo \ (B = \ frac {n} {B} \ log n \) se obtiene cuando \ (B = \ sqrt {n \ log n} \) .

Código de arriba:

\(Código:\)

#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
	typedef long long ll;
	typedef double db;
	#define pf printf
	#define pc putchar
	#define fr(i,x,y) for(register int i=(x);i<=(y);++i)
	#define pfr(i,x,y) for(register int i=(x);i>=(y);--i)
	#define go(x) for(int i=head[u];i;i=e[i].nxt)
	#define enter pc('\n')
	#define space pc(' ')
	#define fir first
	#define sec second
	#define MP make_pair
	const int inf=0x3f3f3f3f;
	const ll inff=1e15;
	inline int read()
	{
		int sum=0,f=1;
		char ch=0;
		while(!isdigit(ch))
		{
			if(ch=='-') f=-1;
			ch=getchar();
		}
		while(isdigit(ch))
		{
			sum=sum*10+(ch^48);
			ch=getchar();
		}
		return sum*f;
	}
	inline void write(int x)
	{
		if(x<0)
		{
			x=-x;
			pc('-');
		}
		if(x>9) write(x/10);
		pc(x%10+'0');
	}
	inline void writeln(int x)
	{
		write(x);
		enter;
	}
	inline void writesp(int x)
	{
		write(x);
		space;
	}
}
using namespace my_std;
const int N=1e5+50;
int n,B,idx,f[N],fat[N],dfn[N],head[N],cnt,ans[N];
struct edge
{
	int to,nxt;
}e[N<<1];
inline void add(int u,int v)
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void dfs(int u,int fa)
{
	fat[u]=fa;
	go(u)
	{
		int v=e[i].to;
		if(v!=fa) dfs(v,u);
	}
	dfn[++idx]=u;
} 
inline int solve(int k)
{
	int ans=0;
	fr(i,1,n) f[i]=1;
	fr(i,1,n)
	{
		int u=dfn[i];
		if(fat[u]&&f[fat[u]]&&f[u])
		{
			if(f[u]+f[fat[u]]>=k)
			{
				++ans,f[fat[u]]=0;
			}
			else f[fat[u]]=max(f[fat[u]],f[u]+1);
		}
	}
	return ans;
}
int main(void)
{
	n=read();
	B=sqrt(n*log(n)/log(2));
	fr(i,1,n-1)
	{
		int u=read(),v=read();
		add(u,v),add(v,u);
	}
	dfs(1,0);
	//fr(i,1,n) writesp(dfn[i]);
	ans[1]=n;
	fr(i,2,B) ans[i]=solve(i);
	for(int i=B+1,l,r;i<=n;i=l+1)
	{
		l=i,r=n;
		int tmp=solve(i);
		while(r-l>1)
		{
			int mid=(l+r)>>1;
			if(solve(mid)==tmp) l=mid;
			else r=mid;
		}
		fr(j,i,l) ans[j]=tmp;
	}
	fr(i,1,n) writeln(ans[i]);
	return 0;
}

Supongo que te gusta

Origin www.cnblogs.com/lgj-lgj/p/12714031.html
Recomendado
Clasificación