zoukankan      html  css  js  c++  java
  • 算法学习————Kruskal重构树

    Kruskal重构树:

    简单来讲,就是在Kruskal算法进行的过程中,我们把最小生成树的边权改为点权,加虚点连边,原树的节点个数变成2n-1个

    Kruskal重构树的性质

    1.根据我们构造的过程,这是一个二叉堆

    2.原树两点之间的边权最大值是重构树上两点Lca的权值

    3.重构树中代表原树中的点的节点全是叶子节点,其余节点都代表了一条边的边权。

    Kruskal重构树的构造

    1. 首先对边排序

    2. 使用并查集辅助加边,每新建一条边时:新建节点index(编号从n+1开始)

    3. 将原有两节点所在集合改为index

    4. 将原有节点与index连边新建节点的权值为当前边的边权

    构建的代码:

            for (int i = 1;i <= m;i++){
    		int u = g[i].u,v = g[i].v,w = g[i].w;
    		int fu = find(u),fv = find(v);
    	//	cout<<"u = "<<u<<" "<<v<<" "<<fu<<" "<<fv<<endl;
    		if (fu != fv){
    			fa[fu] = fa[fv] = ++cnt;
    			val[cnt] = w;
    			add(cnt,fu),add(cnt,fv);
    			if (cnt == 2*n-1) break;
    		}
    	}
    

    例题:NOI2018 归程

    这道题拿到手我们思考,如果有多个路径,我走哪一条,并且我该在什么时候下车呢?

    贪心来想对于一条固定的路径来说,肯定是越晚下车越好,那么一个思路就出来了,我求出每条路径的最晚下车点到家的距离,最小的那一个就是我要走的

    最短距离我们可以先最短路预处理,但是一条一条路径找这样的复杂度显然不优,那我们接着思考,最晚下车点是哪个点呢?就是第一个比水位线低的点,这个点连出的边是最晚下车点到出发点的最小边

    出现了最小边,不难联想到上面Kruskal重构树的性质,边权从大到小排序,建出来的树,两点间的lca就是最小边权

    这样我从起点向上跳,跳到的每一个点,都是他与其他某个点间的最小边权并且这个边权是递减的

    那么在建完kruskal重构树之后,我们可以处理出以每个点为根到家的最短路(子树中的点间的最大边权显然都不超过根的点权),然后每次从起点倍增向上跳到最后一个大于水位线的就好了

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();}
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a;
    }
    const int maxn = 1e6+10,inf = 1e9+7;
    int T,n,m;
    struct node{
    	int tot = 0;
    	int head[maxn],to[maxn],w[maxn],nxt[maxn];
    	inline void add(int u,int v,int k){
    		to[++tot] = v;
    		nxt[tot] = head[u];
    		w[tot] = k;
    		head[u] = tot;
    	}
    	void add(int u,int v){
    		to[++tot] = v;
    		nxt[tot] = head[u];
    		head[u] = tot;
    	}
    }ed1,ed2;
    struct ask{
    	int u,v,a,id;
    }g[maxn],q[maxn];
    bool cmp(ask x,ask y){return x.a > y.a;}
    int dis[maxn];
    bool vis[maxn];
    inline void Dij(){
    	priority_queue<pair<int,int> > q;
    	for (int i = 1;i <= n;i++) dis[i] = inf,vis[i] = 0;
    	dis[1] = 0;
    	q.push(make_pair(0,1));
    	while (!q.empty()){
    		int x = q.top().second;q.pop();
    		if (vis[x]) continue;
    		vis[x] = 1;
    		for (int i = ed1.head[x];i;i = ed1.nxt[i]){
    			int to = ed1.to[i];
    			if (dis[to] > dis[x]+ed1.w[i]){
    				dis[to] = dis[x]+ed1.w[i];
    				q.push(make_pair(-dis[to],to));
    			}
    		}
    	} 
    }
    int fa[maxn],val[maxn],road[maxn];
    inline void init(){
    	for (int i = 1;i <= 2*n;i++) fa[i] = i,ed1.head[i] = ed2.head[i] = 0;
    	ed1.tot = ed2.tot = 0;
    	for (int i = n+1;i <= 2*n-1;i++) road[i] = inf;
    }
    int find(int x){return (x == fa[x]) ? x : fa[x] = find(fa[x]);}
    int Q,k,s;
    int dep[maxn],f[maxn][30];
    void dfs(int x){
    	dep[x] = dep[f[x][0]]+1;
    	for (int i = 1;i <= 22;i++) f[x][i] = f[f[x][i-1]][i-1];
    	for (int i = ed2.head[x];i;i = ed2.nxt[i]){
    		int to = ed2.to[i];
    		if (to == f[x][0]) continue;
    		f[to][0] = x;
    		dfs(to);
    		road[x] = min(road[x],road[to]);
    	}
    }
    int query(int x,int y){
    	for (int i = 22;i >= 0;i--) if (dep[x]-(1 << i) > 0&&val[f[x][i]] > y) x = f[x][i];
    	return road[x];
    }
    int main(){
    	freopen("return.in","r",stdin);
    	freopen("return.out","w",stdout);
    //	freopen("in.in","r",stdin);
    //	freopen("out.out","w",stdout);
    	T = read();
    	while (T--){
    		n = read(),m = read();int lst = 0;
    		init();
    		for (int i = 1;i <= m;i++){
    			int u = read(),v = read(),l = read(),a = read();
    			ed1.add(u,v,l),ed1.add(v,u,l);
    			g[i].u = u,g[i].v = v,g[i].a = a;
    		}
    		Dij();
    		for (int i = 1;i <= n;i++) road[i] = dis[i];
    		sort(g+1,g+m+1,cmp); 
    //		for (int i = 1;i <= m;i++) cout<<"g = "<<g[i].u<<" "<<g[i].v<<" "<<g[i].a<<endl;
    		Q = read(),k = read(),s = read();
    		int cnt = n;
    		for (int i = 1;i <= m;i++){
    			int u = g[i].u,v = g[i].v,a = g[i].a;
    			int fu = find(u),fv = find(v);
    //			cout<<"fu = "<<fu<<" "<<fv<<endl;
    			if (fu != fv){
    				val[++cnt] = a;
    				fa[fu] = cnt,fa[fv] = cnt;
    				ed2.add(cnt,fu),ed2.add(cnt,fv);
    			}
    //			cout<<"cnt = "<<cnt<<endl;
    			if (cnt == 2*n-1) break;
    		}
    //		cout<<"111111111111111"<<endl;
    		dfs(cnt);
    		while (Q--){
    			int v = read(),p = read();
    			v = (v+lst*k-1) % n+1,p = (p+lst*k) % (s+1);
    			lst = query(v,p);
    			printf("%d
    ",lst);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    强化学习的基本迭代方法
    基于文本描述的事务聚类
    学习强化学习之前需要掌握的3种技能
    其它 华硕 ASAU S4100U 系统安装 win10安装 重装系统 Invalid Partition Table 解决
    数据分析 一些基本的知识
    Python 取样式的内容 合并多个文件的样式 自定义样式
    电商 Python 生成补单公司需要的评论格式3
    SpringBlade 本地图片上传 生成缩略图
    SQL Server 字符串截取
    SpringBlade 本地图片上传
  • 原文地址:https://www.cnblogs.com/little-uu/p/14961808.html
Copyright © 2011-2022 走看看