Landmine

Description

给定 \(n\) 个点的树,带边权。每个点有一个半径,从该点能走一步到达半径以内的其他点。对于每个点,询问至少走几步能到达一号点。

Solution

树上邻域问题,考虑建出点分树,维护新的父子关系。对每个点,不断跳父亲,然后查看哪些点能到达,建出反向边,BFS。容易发现能到达的点的距离是一个前缀,考虑用指针维护,已经访问过的点就删去,均摊 O(n\log n)。由于要排序,所以最后是 \(O(n\log^2 n)\)。主要熟悉一下写法,递归的时候注意全局变量的改变是否会产生错误。

以及 hdu 里面关同步流的 cin 读写速度是最快的……

#include<iostream> 
#include<vector>
#include<algorithm>
#include<queue>
#include<cassert>
using namespace std;

typedef long long ll;
typedef pair<int,ll> E;

const int N=1e5+7;

int sz[N],ans[N],nd,Fa[N],p[N],dep[N],cur;
ll r[N],D[18][N];
vector<E> g[N],C[N];
bool vis[N];
queue<int> Q;

int count(int u,int f){
	int ret=1;
	for(E v:g[u])
	if(v.first!=f&&!vis[v.first])
		ret+=count(v.first,u);
	return ret;
}

int Min,s,rt;
void find_rt(int u,int f){
	sz[u]=1; int tmp=0;
	for(E v:g[u])
		if(v.first!=f&&!vis[v.first]){
			find_rt(v.first,u);
			sz[u]+=sz[v.first],tmp=max(sz[v.first],tmp);
		}
	tmp=max(s-sz[u],tmp);
	if(tmp<Min) Min=tmp,rt=u;
}

void calc_dis(vector<E> &V,int u,int f){
	C[rt].push_back(E (u,r[u]-D[cur][u]));
	for(E v:g[u])
	if(v.first!=f&&!vis[v.first]){
		D[cur][v.first]=D[cur][u]+v.second;
		calc_dis(V,v.first,u);
	}
}

inline bool Cmp(const E &X,const E &Y){return X.second<Y.second;}

void Dfs(int u,int f){
	Min=s=count(u,u),rt=u,find_rt(u,u);
	Fa[rt]=f,cur=dep[rt]=dep[f]+1;
	D[cur][rt]=0,calc_dis(C[rt],rt,rt),vis[rt]=1;
	sort(C[rt].begin(),C[rt].end(),Cmp);
	int gg=rt;
	for(E v:g[gg])
		if(!vis[v.first]&&v.first!=f) Dfs(v.first,gg);
}

int main(){
	ios::sync_with_stdio(false);
	int T; cin>>T;
	while(T--){
		int n,nd; cin>>n; nd=n;
		for(int i=2;i<=n;i++) cin>>r[i];
		for(int i=1;i<n;i++){
			int u,v; ll dis_;
			cin>>u>>v>>dis_;
			g[u].push_back(E (v,dis_));
			g[v].push_back(E (u,dis_));
		}
		Dfs(1,0),Q.push(1);
		for(int i=1;i<=n;i++)
			vis[i]=0,p[i]=C[i].size()-1;
		vis[1]=1;
		while(!Q.empty()){
			int u=Q.front(),y=u; Q.pop();
			while(y){
				while(~p[y]){
					E x=C[y][p[y]];
					if(x.second<D[dep[y]][u]) break;
					if(!vis[x.first]){
						ans[x.first]=ans[u]+1;
						Q.push(x.first),vis[x.first]=1;
					}
					p[y]--;
				}
				y=Fa[y];
			}
		}
		for(int i=2;i<=n;i++)
			printf("%d ",ans[i]? ans[i]:-1);
		printf("\n");
		for(int i=1;i<=n;i++){
			C[i].clear(),g[i].clear();
			dep[i]=p[i]=Fa[i]=sz[i]=ans[i]=vis[i]=0;
		}
	}
}
posted @ 2023-09-21 08:49  Kreap  阅读(41)  评论(0编辑  收藏  举报