H - Traveling Plan 最小生成树+路径的最大值
这个题目太可惜了,想错了一点点,本来是想把0的点都删去,但是想了好久都不知道怎么删,最后看了题解发现可以不用删边,把边的大小变成等效删边的大小即可
题解:
参考题目:lh的简单图论
多源最短路求出每一个点到最近的补给点的距离 $d[i] $
那么,任意两条边的距离就更新为:(d[x]+d[y]+w)
然后就是最小生成树将图转化成树,最后就是用倍增的LCA顺便求一下最大值。
[红蓝图](https://ac.nowcoder.com/acm/contest/7745/F) kruskal重构树+dfs序+线段树合并
题解:
如果不会kruskal重构树,建议先写 [D. Graph and Queries 并查集+线段树+kruskal重构树](https://www.cnblogs.com/EchoZQN/p/13804989.html)
* 首先对查询按照 t 从大到小排序,然后按照权值从大到小建一棵kruskal重构树,然后dfs求出每一个节点的dfs序,顺便求出每一个询问节点的子树节点。
* 对于每一个节点都建一棵动态开点的线段树,然后对查询按照 t 从小到大排序,边建线段树边输出询问。
~~~c++
#include <bits/stdc++.h>
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
struct node{
int u,v;
ll w;
node(int u=0,int v=0,ll w=0):u(u),v(v),w(w){}
}e[maxn];
int a[maxn],Head[maxn],To[maxn<<1],Nxt[maxn<<1],CNT;
ll w[maxn<<1];
void add(int u,int v,int c){
++CNT,To[CNT]=v,Nxt[CNT]=Head[u],w[CNT]=c,Head[u]=CNT;
++CNT,To[CNT]=u,Nxt[CNT]=Head[v],w[CNT]=c,Head[v]=CNT;
}
struct heapnode{
int u;
ll d;
heapnode(int u=0,ll d=0):u(u),d(d){}
bool operator<(const heapnode& a)const{
return a.d<d;
}
};
priority_queue<heapnode>que;
ll dis[maxn];
bool vis[maxn];
int f[maxn];
int find(int x){
return f[x]==x?x:f[x] = find(f[x]);
}
void unite(int x,int y){
x = find(x),y = find(y);
if(x == y) return ;
f[x] = y;
}
bool same(int x,int y){
return find(x)==find(y);
}
int head[maxn],to[maxn<<1],cost[maxn<<1],nxt[maxn<<1],cnt;
void ADD(int u,int v,int w){
++cnt,to[cnt]=v,cost[cnt]=w,nxt[cnt]=head[u],head[u]=cnt;
++cnt,to[cnt]=u,cost[cnt]=w,nxt[cnt]=head[v],head[v]=cnt;
}
bool cmp(node a,node b){
return a.w<b.w;
}
ll gw[maxn][22];
int fa[maxn][22],dep[maxn];
void dfs(int u,int pre,int deep){
fa[u][0] = pre,dep[u] = deep;
// printf("u = %d pre = %d deep=%d
", u,pre,deep);
for(int i=head[u];i;i=nxt[i]){
int v = to[i];
if(v == pre) continue;
gw[v][0] = cost[i];
dfs(v,u,deep+1);
}
}
void init(int n){
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++){
fa[i][j] = fa[fa[i][j-1]][j-1];
gw[i][j] = max(gw[i][j-1],gw[fa[i][j-1]][j-1]);
}
}
}
int n,m;
ll LCA(int u,int v){
ll ans = 0;
if(dep[u]<dep[v]) swap(u,v);
int d = dep[u]-dep[v];
for(int i=0;(1<<i)<=d;i++){
if((1<<i)&d) {
ans = max(ans,gw[u][i]);
u = fa[u][i];
}
}
for (int i = (int)log(n); i >= 0; i--){//一起往上走
if(fa[u][i]!=fa[v][i]){
ans = max(ans, gw[u][i]);
ans = max(ans, gw[v][i]);
u = fa[u][i];
v = fa[v][i];
}
}
if(u!=v){ //最后一步
ans = max(ans, gw[u][0]);
ans = max(ans, gw[v][0]);
}
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(a[i]==1) que.push(heapnode(i,0));
else dis[i] = inf64;
f[i] = i;
}
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[i] = node(u,v,w);
add(u,v,w);
}
while(!que.empty()){
heapnode x = que.top();que.pop();
int u = x.u;
if(vis[u]) continue;
vis[u] = true;
for(int i=Head[u];i;i=Nxt[i]){
int v = To[i];
if(dis[v]>dis[u]+w[i]){
dis[v] = dis[u] + w[i];
que.push(heapnode(v,dis[v]));
}
}
}
// for(int i=1;i<=n;i++){
// printf("dis[%d]=%lld
", i,dis[i]);
// }
for(int i=1;i<=m;i++) {
e[i].w += dis[e[i].u]+dis[e[i].v];
// printf("e[%d].z=%lld
", i,e[i].w);
}
sort(e+1,e+1+m,cmp);
for(int i=1;i<=m;i++){
int u = e[i].u,v = e[i].v;
if(same(u,v)) continue;
unite(u,v);
ADD(u,v,e[i].w);
}
dfs(1,0,1),init(n);
int q;
scanf("%d",&q);
while(q--){
int x,y;
scanf("%d%d",&x,&y);
ll ans = LCA(x,y);
printf("%lld
", ans);
}
return 0;
}
~~~