链接:http://acm.hdu.edu.cn/showproblem.php?pid=4679
题意:给定一颗树,每条边有一个权值w,问切掉哪条边之后,分成的两颗树的较大的直径*切掉边的权值最小?如果存在多条边使得结果相同,输出边id最小的
思路:
dept一次找出最深的节点,之后以最深的节点出发(rt1)dept找到树的直径(即找到rt2);将路径保存在f[]中;
之后分别从rt1/rt2进行深搜,找到以一个节点为根的树的直径,这样在每次dfs之后,可以求出每条边的一边的最值,这样两次取max之后就求出了切掉该边之后得到的结果
注:
如果改变在整棵树的直径上,需要取出以该棵树为根的树的直径maxn[0][v];否则就直接取整棵树的直径即可;
在dfs递推出以某根为子树的直径时,可能直径不过根节点所以要将子子树的直径递推到子树上;
1 #include<bits/stdc++.h> 2 #pragma comment(linker, "/STACK:1024000000,1024000000") //加栈 3 using namespace std; 4 #define rep0(i,l,r) for(int i = (l);i < (r);i++) 5 #define rep1(i,l,r) for(int i = (l);i <= (r);i++) 6 #define rep_0(i,r,l) for(int i = (r);i > (l);i--) 7 #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) 8 #define MS0(a) memset(a,0,sizeof(a)) 9 #define MS1(a) memset(a,-1,sizeof(a)) 10 #define MSi(a) memset(a,0x3f,sizeof(a)) 11 #define inf 0x3f3f3f3f 12 #define lson l, m, rt << 1 13 #define rson m+1, r, rt << 1|1 14 typedef pair<int,int> PII; 15 #define A first 16 #define B second 17 #define MK make_pair 18 typedef long long ll; 19 typedef unsigned int uint; 20 template<typename T> 21 void read1(T &m) 22 { 23 T x=0,f=1;char ch=getchar(); 24 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 25 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 26 m = x*f; 27 } 28 template<typename T> 29 void read2(T &a,T &b){read1(a);read1(b);} 30 template<typename T> 31 void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} 32 template<typename T> 33 void out(T a) 34 { 35 if(a>9) out(a/10); 36 putchar(a%10+‘0‘); 37 } 38 #define N 100007 39 int head[N<<1],tot; 40 struct edge{ 41 int to,w,id,Next; 42 }e[N<<1]; 43 void ins(int a,int b,int w,int id) 44 { 45 e[++tot].Next = head[a]; 46 e[tot].to = b; 47 e[tot].w = w; 48 e[tot].id = id; 49 head[a] = tot; 50 } 51 int dep[N],p[N]; 52 void dept(int u,int pre) 53 { 54 p[u] = pre; 55 dep[u] = dep[pre] + 1; 56 for(int id = head[u];id;id = e[id].Next){ 57 int v = e[id].to; 58 if(v == pre) continue; 59 dept(v,u); 60 } 61 } 62 int f[N],maxlen;//树的直径 63 int aux[N]; 64 int maxn[3][N]; 65 void dfs(int u,int pre) 66 { 67 maxn[0][u] = maxn[1][u] = maxn[2][u] = 0; 68 for(int id = head[u];id;id = e[id].Next){ 69 int v = e[id].to; 70 if(v == pre) continue; 71 dfs(v,u); 72 if(maxn[1][u] <= maxn[1][v]+1){ 73 maxn[2][u] = maxn[1][u]; 74 maxn[1][u] = maxn[1][v]+1; 75 }else if(maxn[2][u] < maxn[1][v]+1) 76 maxn[2][u] = maxn[1][v]+1; 77 if(maxn[0][u] < maxn[0][v]) //**可能树的直径不过根节点; 78 maxn[0][u] = maxn[0][v]; 79 } 80 maxn[0][u] = max(maxn[0][u],maxn[1][u] + maxn[2][u]); //以u为根的子树的直径 81 } 82 void solve(int u,int pre) 83 { 84 for(int id = head[u];id;id = e[id].Next){ 85 int v = e[id].to, w = e[id].w; 86 if(v == pre) continue; 87 if(f[u] && f[v]){ //边在直径上 88 aux[e[id].id] = max(aux[e[id].id],w*maxn[0][v]); 89 }else{ 90 aux[e[id].id] = max(aux[e[id].id],w*maxlen); 91 } 92 solve(v,u); 93 } 94 } 95 int main() 96 { 97 //freopen("data.txt","r",stdin); 98 //freopen("out.txt","w",stdout); 99 int kase = 1,T,n; 100 read1(T); 101 while(T--){ 102 MS0(head);tot = 0; 103 MS0(f); 104 read1(n); 105 rep0(i,1,n){ 106 int u,v,w; 107 read3(u,v,w); 108 ins(u,v,w,i);ins(v,u,w,i); 109 } 110 dep[0] = 0; 111 dept(1,0); 112 int rt1 ,rt2 ,d = 0; 113 rep1(i,1,n) if(d < dep[i]) d = dep[i],rt1 = i; 114 dept(rt1,0); 115 d = 0; 116 rep1(i,1,n) if(d < dep[i]) d = dep[i],rt2 = i; 117 maxlen = d-1; //求出树的直径;以及两端的节点标号 118 int index = rt2; 119 while(index){ 120 f[index] = 1; 121 index = p[index]; //从树直径的终点递推到起点 122 } 123 MS0(aux); 124 dfs(rt1,-1); 125 solve(rt1,0); 126 dfs(rt2,-1); 127 solve(rt2,0); 128 int ans = inf; 129 rep0(i,1,n){ 130 if(ans > aux[i]) ans = aux[i],index = i; 131 } 132 printf("Case #%d: %d\n",kase++,index); 133 } 134 return 0; 135 }
时间: 2024-11-05 11:05:34