当前位置: 首页 > news >正文

kruscal重构树

构造:

  • 把最小生成树上的边从小到大取出来。

这一步在实现上相当于边做 Kruskal 边构造重构树。

利用这个性质,我们可以找到到点 x 的简单路径上的边最大权值的最小值 ≤val 的所有点 y。可以发现都在 Kruskal 重构树上的某一棵子树内,且恰好为该子树的所有叶节点。

  • 设这条边的为 x 与 y 连边,那么我们新建节点 now,将 now 连向 x,y,将 now 的点权设为这条边的边权,x 与 y 之间不连边。注意这里向 x 连边实际上指的是向 x 所在子树的根节点连边。

  • 建完最小生成树之后,重构树也就建好了。

  • 这是一张无向带权图。

  • 这是这张图的最小生成树。

    我们将每条边从小到大建立 Kruskal 重构树。

  • 这样我们就建好了这个图的 Kruskal 重构树。

  • //kruscal重构树int idx = n;for(auto &[x,y,w]:edge){int fx = root(x);int fy = root(y);if(fx != fy){idx ++ ;pre[fx] = pre[fy] = idx;val[idx] = w;g[idx].push_back(fx);g[idx].push_back(fy);if(idx == 2 * n - 1)break;}}

    性质:

  • 是一棵二叉树。

  • 如果是按最小生成树建立的话是一个大根堆。

  • 强大性质:原图中两个点间所有路径上的边最大权值的最小值 = 最小生成树上两点简单路径的边最大权值 = Kruskal 重构树上两点 LCA 的点权。

 例题:

1706E - Qpwoeirut and Vertices

我们将这条边的编号定义为它的边权。通过 Kruskal 生成树算法,连边时断开这条边,而是新建一个点,让这个新点来连接两点,新点的点权为原来连边的权值。这就是 Kruskal 重构树。

得到 Kruskal 重构树后,为了 u 和 v 连通,连接的边的最大值的最小值,即为 u 和 v 的最近公共祖先的点权。通过倍增法求出最近公共祖先即可。

对于所有的 i(1≤i<n),我们可以先求出使 i 和 i+1 连通的代价(设为 ansi​)。然后,建造线段树,预处理出区间最大值。

最后,询问 l,r 本质上就是使 [l,1+1],[l+1,l+2],…[r−1,r] 都连通,那么答案就是 maxi=lr−1​ansi​。利用线段树求出即可。

代码:

#pragma GCC optimize(2,"Ofast","inline")
#include <bits/stdc++.h>#define int long long
#define double long double
#define ull unsigned long long
#define fi first 
#define se second
#define ls(p) p<<1
#define rs(p) (p<<1)|1
#define YES cout<<"YES\n"
#define NO cout<<"NO\n"
#define Yes cout<<"Yes\n"
#define No cout<<"No\n"
#define sp(x) fixed << setprecision(x)
#define all(v) v.begin(),v.end()using namespace std;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ull rnd() { return (unsigned long long)rng(); }const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 5;
int n,m,q;
vector<int>g[N];
struct node{int x,y,w;bool operator<(const node &u)const{return w < u.w;}
};
vector<node>edge;
int pre[N];
int val[N];//点权
int fa[N][24],dep[N];
int tr[N];
int b[N];int root(int x){return pre[x] = (pre[x] == x) ? x : root(pre[x]);
}void init(){edge.clear();for(int i=1;i<=n*2LL;i++){dep[i] = 0;g[i].clear();pre[i] = i;for(int j=1;j<=20;j++)fa[i][j] = 0;}return;
}void dfs(int x,int p){//p为父亲dep[x]=dep[p]+1;fa[x][0]=p;for(int i=1;i<=20;i++){fa[x][i]=fa[fa[x][i-1]][i-1];}for(const auto &y:g[x]){if(y==p)continue;dfs(y,x);}
}int lca(int x,int y){if(dep[x]<dep[y])swap(x,y);for(int i=20;i>=0;i--){if(dep[fa[x][i]]>=dep[y])x=fa[x][i];}if(x==y)return x;for(int i=20;i>=0;i--){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}}return fa[x][0];
}void push_up(int p){tr[p] = max(tr[ls(p)] , tr[rs(p)]);return;
}void build(int p,int l,int r){if(l == r){tr[p] = b[l];return;}int mid = l+r>>1;build(ls(p) , l , mid);build(rs(p) , mid + 1 , r);push_up(p);return;
}int query(int p,int l,int r,int nl,int nr){if(nl <= l && r <= nr){return tr[p];}int mid = l+r>>1;int res = 0;if(nl <= mid)res = max(res , query(ls(p) , l , mid , nl , nr));if(nr > mid)res = max(res , query(rs(p) , mid + 1 , r , nl , nr));return res;
}void solve(){cin>>n>>m>>q;init();for(int i=1;i<=m;i++){int x,y;cin>>x>>y;int w = i;edge.push_back({x , y , w});}sort(all(edge));//kruscal重构树int idx = n;for(auto &[x,y,w]:edge){int fx = root(x);int fy = root(y);if(fx != fy){idx ++ ;pre[fx] = pre[fy] = idx;val[idx] = w;g[idx].push_back(fx);g[idx].push_back(fy);if(idx == 2 * n - 1)break;}}dfs(idx , 0);for(int i=1;i<n;i++){int p = lca(i , i + 1);b[i] = val[p];}build(1 , 1 , n - 1);while(q--){int l,r;cin>>l>>r;if(l == r){cout<<0<<" ";continue;}cout<<query(1 , 1 , n - 1 , l , r - 1)<<" ";}cout<<"\n";return;}signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);time_t Start = clock();int T = 1;cin >> T;while (T -- ){solve();}time_t End = clock(); time_t Run_time = End - Start;//cout<<"\n"<<Run_time<<"ms"<<"\n"; return 0;
}

http://www.lryc.cn/news/602593.html

相关文章:

  • 【Java EE】多线程-初阶-线程的状态
  • Ettus USRP X410/X440 运行 ADC 自校准
  • ubuntu qt环境下出现No suitable kits found解决方案
  • 2025最新Mybatis-plus教程(三)
  • 目前市面上有Android 16KB的手机吗
  • 【Bluedroid】bta_av_sink_media_callback(BTA_AV_SINK_MEDIA_CFG_EVT)流程源码分析
  • OSPF路由协议(上)
  • Linux驱动22 --- RV1126 环境搭建设备树修改
  • 【Linux篇】进程间通信:进程IPC
  • java每日精进 7.28【流程设计6.0(泳池和泳道)】
  • 重生之我在暑假学习微服务第三天《Docker-上篇》
  • 采用黑翅鸢优化算法BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量回归预测,多输入单输出(Matlab)
  • 轻资产革命:连合直租如何用DaaS模式重塑企业资产逻辑
  • 【Apache Tomcat】
  • 设计模式实战:自定义SpringIOC(理论分析)
  • 中国汽车能源消耗量(2010-2024年)
  • 力扣17:电话号码的字母组合
  • 设计模式(二十四)行为型:访问者模式详解
  • ADB+Python控制(有线/无线) Scrcpy+按键映射(推荐)
  • 【学习笔记】AD7708/18(1)-理解官网的参考代码
  • MacBook IOS操作系统格式化U盘FAT32
  • 【深度解析】R语言与作物模型(以DSSAT模型为例)融合应用
  • 分布式微服务--核心组件与架构关系(一)
  • R语言简介(附电子书资料)
  • Leetcode_349.两个数组的交集
  • JavaScript手录09-内置对象【String对象】
  • 6.2 总线事务和定时 (答案见原书 P295)
  • 基于Flask的智能停车场管理系统开发实践
  • C语言:20250728学习(指针)
  • 使用node-cron实现Node.js定时任务