gym102452C Construcción de ranchos 2019ICPC Hong Kong Live Competition

https://codeforces.com/gym/102452/problem/C

Cuántos de estos caminos cumplen las condiciones es un problema de división y conquista de puntos de un vistazo, pero no lo he escrito en más de medio año. . . Afortunadamente, después de decirle a los compañeros de equipo, los compañeros de equipo tienen 1A durante una hora. Permítanme inventarme esta pregunta y revisar el punto de dividir y conquistar. No siempre puedes confiar en tus compañeros de equipo. . .

Primero, la condición para formar un polígono simple es suma> 2 * mx, que puede ser análoga a que la suma de los dos lados del triángulo sea mayor que el tercer lado.

Dado que la longitud del lado de esta pregunta es el nivel 1e9, tenemos que usar una matriz de árbol para mantener. Sacamos los subárboles que no están marcados como verdaderos, encontramos la suma de la longitud de la ruta desde el nodo raíz hasta cada punto y el valor máximo mx en la ruta, y luego discretizamos todas las sumas de la longitud de la ruta, y luego ordenamos mx. Agréguelos a la matriz de árbol a su vez, y luego el valor máximo de las rutas guardadas en la matriz de árbol <mx de la ruta enumerada actual, para que pueda encontrar directamente la posición que solo satisface el límite superior en la matriz de peso discretizada, y luego puede usarla La suma del prefijo encuentra cuántos se pueden combinar con la ruta actual para formar una ruta que cumpla las condiciones.

Dado que debe ser discretizado, es mejor utilizar la redacción de tolerancia y exclusión, puede averiguar la longitud de todos los caminos y sacar la tolerancia

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> p;
const int maxl=2e5+10;

int n,len,tot;ll ans;
ll a[maxl],num[maxl],b[maxl],dis[maxl];
vector<int> e[maxl];
vector<p> pth;
bool vis[maxl];

struct ctr
{
	int ans,n,mi;
	int son[maxl];
	inline void dfs(int u,int fa)
	{
		son[u]=1;int ret=0;
		for(int v:e[u])
		if(!vis[v] && v!=fa)
		{
			dfs(v,u);
			son[u]+=son[v];
			ret=max(son[v],ret);
		}
		ret=max(ret,n-son[u]);
		if(ret<mi)
		{
			ans=u;
			mi=ret;
		}
	}
	inline int getct(int u)
	{
		ans=0;mi=2e9;
		dfs(u,0);
		return ans;
	}
}ct;

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),e[i].clear(),vis[i]=false;
	int u,v;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
}

inline ll getsum(int i)
{
	ll ret=0;
	while(i)
	{
		ret+=b[i];
		i-=i&-i;
	}
	return ret;
}
inline void add(int i,ll val,int n)
{
	while(i<=n)
	{
		b[i]+=val;
		i+=i&-i;
	}
}

inline void getval(int u,ll mx,ll sum,int fa)
{
	mx=max(mx,a[u]);sum+=a[u];
	pth.push_back({mx,sum});
	for(int v:e[u])
	if(!vis[v] && v!=fa)
		getval(v,mx,sum,u);
}

inline ll calc(int u,ll w,int fa)
{
	tot=0;pth.clear();
	getval(u,w,w,fa);
	for(p d:pth)
		num[++tot]=d.second;
	sort(num+1,num+1+tot);
	tot=unique(num+1,num+1+tot)-num-1;
	sort(pth.begin(),pth.end());
	ll mx,sum,val=(w>0)?w:a[u],ret=0;int pos;
	for(p d:pth)
	{
		mx=d.first;sum=d.second;
		pos=upper_bound(num+1,num+1+tot,2*mx-sum+val)-num;
		if(pos<=tot)
			ret+=getsum(tot)-getsum(pos-1);
		pos=lower_bound(num+1,num+1+tot,sum)-num;
		add(pos,1ll,tot);
	}
	for(p d:pth)
	{
		sum=d.second;
		pos=lower_bound(num+1,num+1+tot,sum)-num;
		add(pos,-1ll,tot);
	}
	return ret;
}

inline void solv(int u)
{
	vis[u]=true;ans+=calc(u,0ll,0);
	int rt;
	for(int v:e[u])
	if(!vis[v])
	{
		ans-=calc(v,a[u],u);
		ct.n=ct.son[v];
		rt=ct.getct(v);
		solv(rt);
	}
}

inline void mainwork()
{
	ct.n=n;
	int rt=ct.getct(1);
	ans=0;
	solv(rt);
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

Supongo que te gusta

Origin blog.csdn.net/liufengwei1/article/details/108478079
Recomendado
Clasificación