标签:
题意:
一颗树,定义一条路径的权值等于路径的边权之和,需要求这颗树所有路径中权值的最大值
思路:
考虑到路径权值与点权的最值有关,而最值的问题通常可以通过排序就行处理,于是想到先把点权排序。
容易看出如果某条路径的权值是通过某个点算出的最小 ,那么肯定这条路径肯定不会经过权值更小的点,于是有了两种处理思路
1.按点权从小到大删点,对于即将删除的点,比他权值小的点已经被删去了,所以只要在当前状态的森林里找一条最长路径乘以次点权就可以更新答案
2.按点权从大到小加点,显然新加进来的点权值最小,当前树里的任何路径的点权最小值都不会小于新加进来的点,所以可以通过维护直径来更新答案
对于思路1,如果是一条链的话,对于一个将要删除的点,可以直接二分得到当前点附近已经被删除的点并更新答案,然而在树里面就不太好从处理了,至少我肯定是不会的
于是考虑思路2:
加点建树很明显可以通过并查集维护
但是在树的合并过程中怎么维护直径呢?这里需要用到一个定理。。一颗树的直径的两个端点一定是他子树直径的端点
于是就可以进行直径的维护了,具体求距离可以选择logn的lca
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 long long f[200010]; 4 // 节点编号[1,n] 5 // 最大节点数 6 #define MAXN 200010 7 // 满足2^M > MAXN 8 #define M 20 9 struct node 10 { 11 long long to,val; 12 }; 13 struct tree 14 { 15 long long r,x,y; 16 void clear() 17 { 18 r=0; 19 x=y=-1; 20 } 21 }t[100010]; 22 vector<node>g[200010]; 23 long long d[200010]; 24 long long n; 25 int a[200010]; 26 long long ans; 27 long long ch[MAXN]={0}; // 节点i下面的孩子的个数(包括i) 28 long long fa[MAXN][M+2]; // ch[i][j]表示与节点i距离为2^j的i的祖先 29 long long len[MAXN][M+2]; 30 long long deep[MAXN]={0}; // i的深度(根节点的深度为1) 31 // 初始化deep数组,ch数组,fa数组的初始值 32 // 默认根节点为1 33 long long dfs(int cur=1, int father = 0,long long val=0) 34 { 35 deep[cur] = deep[father]+1; 36 fa[cur][0] = father; 37 len[cur][0]=val; 38 ch[cur] = 1; 39 int sz = g[cur].size(); 40 for(int i=0;i<sz;i++) 41 { 42 if(g[cur][i].to != father) 43 ch[cur] += dfs(g[cur][i].to,cur,g[cur][i].val); 44 } 45 return ch[cur]; 46 } 47 // 初始化fa数组 48 void initFa(int n) 49 { 50 for(int i=1;i<=19;i++) 51 for(int node=1;node<=n;node++) 52 { 53 fa[node][i] = fa[fa[node][i-1]][i-1]; 54 len[node][i]= len[fa[node][i-1]][i-1]+len[node][i-1]; 55 } 56 } 57 // 将node上升height的高度 58 int binaryRaise(int node, int height,long long &val) 59 { 60 val=0; 61 for(int i=M; i>=0; i--) 62 { 63 if(fa[node][i] && height >= (1<<i)) 64 { 65 val+=len[node][i]; 66 node = fa[node][i]; 67 height -= (1<<i); 68 } 69 } 70 return node; 71 } 72 // a的深度比b大 73 long long lca(int a, int b) 74 { 75 if(a==0||b==0) 76 return -1; 77 // 先移动a到与b同样深度的地方 78 if(deep[a]<deep[b]) 79 swap(a,b); 80 long long res=0; 81 a = binaryRaise(a, deep[a]-deep[b],res); 82 if(a==b) // 此时,b就是a和b的公共祖先 83 //return a; 84 return res; 85 for(int i=M;i>=0;i--) 86 { 87 if(a!=b && fa[a][i]!=fa[b][i]) 88 { 89 res+=len[a][i]; 90 a = fa[a][i]; 91 res+=len[b][i]; 92 b = fa[b][i]; 93 } 94 } 95 96 return res+len[a][0]+len[b][0]; 97 } 98 int find(int a) 99 { 100 if(f[a]==a||f[a]==-1) 101 return f[a]=a; 102 f[a]=find(f[f[a]]); 103 t[a]=t[f[a]]; 104 return f[a]; 105 } 106 int uni(int a,int b) 107 { 108 int x=find(a),y=find(b); 109 return f[y]=x; 110 } 111 bool issame(int a,int b) 112 { 113 return find(a)==find(b); 114 } 115 116 bool cmp(int a,int b) 117 { 118 return d[a]>d[b]; 119 } 120 void merg(int a,int b) 121 { 122 int fb=find(b); 123 long long l11=lca(t[a].x,t[fb].x); 124 long long l12=lca(t[a].x,t[fb].y); 125 long long l21=lca(t[a].y,t[fb].x); 126 long long l22=lca(t[a].y,t[fb].y); 127 long long maxl=max(max(max(max(max(l11,l12),l21),l22),t[a].r),t[fb].r); 128 int x1=t[a].x; 129 int x2=t[fb].x; 130 int y1=t[a].y; 131 int y2=t[fb].y; 132 if(l11==maxl) 133 { 134 t[a].x=x1; 135 t[a].y=x2; 136 } 137 if(l12==maxl) 138 { 139 t[a].x=x1; 140 t[a].y=y2; 141 } 142 if(l21==maxl) 143 { 144 t[a].x=y1; 145 t[a].y=x2; 146 } 147 if(l22==maxl) 148 { 149 t[a].x=y1; 150 t[a].y=y2; 151 } 152 if(t[a].r==maxl) 153 { 154 t[a].x=x1; 155 t[a].y=y1; 156 } 157 if(t[fb].r==maxl) 158 { 159 t[a].x=x2; 160 t[a].y=y2; 161 } 162 t[a].r=maxl; 163 f[fb]=a; 164 } 165 void put(int p) 166 { 167 t[p]=tree{0,p,p}; 168 f[p]=p; 169 for(int i=0;i<(int)g[p].size();i++) 170 { 171 int to=g[p][i].to; 172 if(f[to]==-1) 173 continue; 174 merg(p,to); 175 } 176 ans=max(ans,d[p]*t[p].r); 177 } 178 int main() 179 { 180 freopen("in.txt","r",stdin); 181 int T; 182 scanf("%d",&T); 183 while(T--) 184 { 185 memset(ch,0,sizeof(ch)); 186 memset(fa,0,sizeof(fa)); 187 memset(len,0,sizeof(len)); 188 memset(deep,0,sizeof(deep)); 189 //scanf("%I64d",&n); 190 scanf("%lld",&n); 191 for(int i=0;i<=n;i++) 192 g[i].clear(); 193 for(int i=1;i<=n;i++) 194 { 195 scanf("%lld",d+i); 196 a[i-1]=i; 197 } 198 int x,y; 199 long long v; 200 for(int i=1;i<n;i++) 201 { 202 //scanf("%d%d%I64d",&x,&y,&v); 203 scanf("%d%d%lld",&x,&y,&v); 204 g[x].push_back(node{y,v}); 205 g[y].push_back(node{x,v}); 206 } 207 dfs(); 208 initFa(n); 209 sort(a,a+n,cmp); 210 memset(f,-1,sizeof(f)); 211 memset(t,0,sizeof(t)); 212 ans=-1; 213 for(int i=0;i<n;i++) 214 { 215 put(a[i]); 216 } 217 //printf("%I64d\n",ans); 218 printf("%lld\n",ans); 219 } 220 return 0; 221 }
计蒜客 444 / xtuoj 1024 京东的物流路径(并查集+离线lca)
标签:
原文地址:http://www.cnblogs.com/oneshot/p/4682287.html