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;
    }
    
  • 相关阅读:
    【Azure 应用服务】由 Azure Functions runtime is unreachable 的错误消息推导出 ASYNC(异步)和 SYNC(同步)混用而引起ThreadPool耗尽问题
    【Azure API 管理】是否可以将Swagger 的API定义导入导Azure API Management中
    【Azure 应用服务】Azure Function 不能被触发
    【Azure 环境】Azure Key Vault (密钥保管库)中所保管的Keys, Secrets,Certificates是否可以实现数据粒度的权限控制呢?
    【Azure 事件中心】为应用程序网关(Application Gateway with WAF) 配置诊断日志,发送到事件中心
    【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达
    【Azure API 管理】Azure API Management通过请求中的Path来限定其被访问的频率(如1秒一次)
    【Azure 环境】前端Web通过Azure AD获取Token时发生跨域问题(CORS Error)
    【Azure 应用服务】记一次Azure Spring Cloud 的部署错误 (az spring-cloud app deploy -g dev -s testdemo -n demo -p ./hellospring-0.0.1-SNAPSHOT.jar --->>> Failed to wait for deployment instances to be ready)
    【Azure 应用服务】App Service中抓取 Web Job 的 DUMP 办法
  • 原文地址:https://www.cnblogs.com/little-uu/p/14961808.html
Copyright © 2011-2022 走看看