湖南附中模拟day1 瞭望塔
/* 这个题要用到树的性质,一般比较难的图论题会往这方面靠拢,这样用很容易出错,应该先写暴力,然后再去一点点想正解 */ //暴力70分 #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define ll long long using namespace std; const int maxn = 2050; int read(){ char ch=getchar(); int x=0,f=1; while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getchar();}; while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getchar();}; return x*f; } struct edge{ int v; int w; int nxt; }e[maxn*4]; int vis[maxn],d[maxn],flag,n,fa[maxn],tmp,ans; int head[maxn],cnt; vector<int> acc; void ins(int u,int v,int w){ cnt++; e[cnt].v = v; e[cnt].w = w; e[cnt].nxt = head[u]; head[u] = cnt; } void dfs(int u,int f){ for(int i = head[u];i;i = e[i].nxt){ if(e[i].v == f) continue; fa[e[i].v] = u; dfs(e[i].v,u); } } void dfs2(int u){ acc.push_back(u); for(int i = head[u];i;i = e[i].nxt){ if(e[i].v == fa[u]) continue; dfs2(e[i].v); } } void dfs3(int u,int d){ vis[u] = true; for(int i = head[u];i;i = e[i].nxt){ if(vis[e[i].v]) continue; dfs3(e[i].v,d+e[i].w); } tmp = max(tmp,d); //cout<<tmp<<endl; } int get_ans(int t){ ans = 999999; acc.clear(); dfs2(t); //cout<<acc.size()<<endl; for(int i = 0;i < acc.size();i++){ tmp = 0; memset(vis,false,sizeof(vis)); vis[fa[t]] = true; dfs3(acc[i],0); ans = min(tmp,ans); } return ans; } void baoli(){ for(int i = 1;i <= n;i++){ cout<<get_ans(i)<<endl; } } int main(){ freopen("tower.in","r",stdin); freopen("tower.out","w",stdout); n = read(); int u,v,l; for(int i = 1;i < n;i++){ u = read(); v = read(); l = read(); ins(u,v,l); ins(v,u,l); } dfs(1,0); baoli(); return 0; } //正解 #include <cstdio> #include <algorithm> #include <cstdlib> using namespace std; #define N 100010 int h[N], parent[N][20], dmax[N], droot[N], diameter[N], radius[N], end[N]; int n, tote, height; struct edge{ int t, l, n; }e[N * 2]; void adde(int u, int v, int l) { e[++tote].t = v; e[tote].l = l; e[tote].n = h[u]; h[u] = tote; return ; } void dfs1(int u) { for (int i = h[u]; i; i = e[i].n) { int v = e[i].t; if (v == parent[u][0]) continue; parent[v][0] = u; dfs1(v); } return ; } void dfs2(int u) { int dmax2 = 0; dmax[u] = diameter[u] = radius[u] = 0;//分别代表以u为根的最长路径,直径,半径 end[u] = u;//最长路径的叶子节点 for (int i = h[u]; i; i = e[i].n) { int v = e[i].t, l = e[i].l; if (parent[u][0] == v) continue; droot[v] = droot[u] + l;//到路径的距离 dfs2(v);//递归子节点 if (diameter[v] > diameter[u]) {//注意这里,直径有可能不经过根节点,这样半径直接用子树的 diameter[u] = diameter[v]; radius[u] = radius[v]; } if (dmax[v] + l >= dmax[u]) {//最长路径 dmax2 = dmax[u]; dmax[u] = dmax[v] + l; end[u] = end[v]; } else if (dmax[v] + l > dmax2)//次长路径 dmax2 = dmax[v] + l; if (dmax[u] + dmax2 > diameter[u]) {//直径被更新,需要更新半径 diameter[u] = dmax[u] + dmax2; int t = height, z = end[u]; while (t >= 0) { if (parent[z][t] != 0 && (dmax2 + droot[parent[z][t]] - droot[u]) > (dmax[u] + dmax2) / 2) z = parent[z][t];//寻找一个节点,他是直径中所有子节点中,到最长路径叶子节点的长度小于他到次长路径叶子节点的长度的节点中,到前者距离最长的一个 t--; } int l1 = dmax2 + droot[z] - droot[u];//上面提到的到次长叶节点的路径长度 int l2 = diameter[u] - (droot[parent[z][0]] - droot[u]) - dmax2;//这个点的父亲到最长叶节点的路径长度 radius[u] = min(l1, l2);//两者比较,谁更优就选谁,也就是半径长度 } } return ; } int main() { freopen("tower.in", "r", stdin); freopen("tower.out", "w", stdout); scanf("%d",&n); for (int i = 1; i < n; i++) { int u, v, l; scanf("%d%d%d", &u, &v, &l); adde(u, v, l); adde(v, u, l); } dfs1(1);//倍增处理相关 for(int i = 1; i <= 17; i++){ bool flag = false; for (int j = 1; j <= n; j++) { parent[j][i] = parent[parent[j][i - 1]][i - 1];//找祖先 if (parent[j][i] != 0) flag = true; } if (!flag) { height = i;//记录高度 break; } } dfs2(1); for (int i = 1; i <= n; i++) printf("%d\n", radius[i]); fclose(stdin); fclose(stdout); return 0; }