修改图中的边权
Posted 929code
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了修改图中的边权相关的知识,希望对你有一定的参考价值。
给你一个n节点的无向带权连通图,同时告诉你边的端点和权值
对于部分权为-1的边,可以进行修改为任意值,最后使得初始点到目标点最短距离为target
1. Dijkstra
邻接表存储
class Solution
public:
vector<vector<int>> modifiedGraphEdges(int n, vector<vector<int>> &edges, int source, int destination, int target)
vector<pair<int, int>> g[n]; //邻接表
for (int i = 0; i < edges.size(); i++) // 遍历所有边
int x = edges[i][0], y = edges[i][1];
g[x].emplace_back(y, i);
g[y].emplace_back(x, i); // 建图,额外记录边的编号,用于后面修改和返回
int dis[n][2], delta, vis[n];
memset(dis, 0x3f, sizeof(dis));
dis[source][0] = dis[source][1] = 0; //初始化初始节点距离
auto dijkstra = [&](int k) // 这里 k 表示第一次/第二次
memset(vis, 0, sizeof(vis)); //初始都未访问
for (;;) //因为是连通图,跳出条件为找到目标值
int x = -1; //用于贪心找点
for (int i = 0; i < n; ++i) //遍历所有点
if (!vis[i] && (x < 0 || dis[i][k] < dis[x][k])) //找未标记的最近点
x = i;
if (x == destination) // 起点 source 到终点 destination 的最短路已确定
return;
vis[x] = true; // 标记,在后续的循环中无需反复更新 x 到其余点的最短路长度
for (auto [y, id]: g[x]) //遍历x的相邻边
int weight = edges[id][2]; //获取边的权值,这里要修正,但不修改,所以需要暂存,而不是直接使用权值去更新
if (weight == -1) weight = 1; // -1 改成 1,第一次不直接在edge上改,防止丢失修改目标
if (k == 1 && edges[id][2] == -1) //对于可以进行修正的边
// 第二次 Dijkstra,修正,是满足目标值
int w = delta + dis[y][0] - dis[x][1]; //修正的权值
if (w > weight)
edges[id][2] = weight = w; // 直接在 edges 上修改
// 更新最短路
dis[y][k] = min(dis[y][k], dis[x][k] + weight);
;
dijkstra(0);
delta = target - dis[destination][0]; //还需要增加的值
if (delta < 0) // -1 全改为 1 时,最短路比 target 还大
return ;
dijkstra(1);
if (dis[destination][1] < target) // 最短路无法再变大,无法达到 target
return ;
for(auto&edge:edges) //按题目要求修改所有-1权值
if(edge[2]==-1) edge[2] = 1;
return edges;
;
邻接矩阵
POJ 2763 /// 基于边权的树链剖分
题目大意:
给定n个结点,有n-1条无向边,给定每条边的边权
两种操作,第一种:求任意两点之间路径的权值和,第二种:修改树上一点的权值。
因为是一棵树,可以直接把 u点和v点间(假设u为父节点,v为子节点)的边 的边权往下给v点
这样就转换成了点权,那么此时查询 u点到v点之间路径的权值和 的话
由于u点存有 u的父节点到u 的边权,所以应该查询的是 u到v的路径上 的第二个点到v的权值和
修改查询树上两结点间路径长度的函数 int queryPath(int x,int y){ } 中求最后一步的部分 /// 点权版本 if(p[x]>p[y]) swap(x,y); return ans+query(p[x],p[y],1,pos,1); /// 边权版本 if(x==y) return ans; if(dep[x]>dep[y]) swap(x,y); return ans+query(p[son[x]],p[y],root);
#include <stdio.h> #include <cstring> #include <algorithm> using namespace std; #define mem(i,j) memset(i,j,sizeof(i)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define root 1,n,1 const int maxn=1e5+5; int n,q,s; struct QTree { struct EDGE { int to,ne; }e[maxn<<1]; int head[maxn], tot; void add(int u,int v) { e[tot].to=v; e[tot].ne=head[u]; head[u]=tot++; } int fa[maxn], son[maxn], dep[maxn], num[maxn]; int top[maxn], p[maxn], fp[maxn], pos; int sumT[maxn<<2]; void init() { tot=1; mem(head,0); pos=0; mem(son,0); } // --------------------以下是线段树------------------------- void pushup(int rt) { sumT[rt]=sumT[rt<<1]+sumT[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { sumT[rt]=0; return ; } int m=(l+r)>>1; build(lson), build(rson); pushup(rt); } void update(int k,int w,int l,int r,int rt) { if(l==r) { sumT[rt]=w; return; } int m=(l+r)>>1; if(k<=m) update(k,w,lson); else update(k,w,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l && r<=R) return sumT[rt]; int m=(l+r)>>1, res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } // --------------------以上是线段树------------------------- // --------------------以下是树链剖分------------------------- void dfs1(int u,int pre,int d) { dep[u]=d; fa[u]=pre; num[u]=1; for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=fa[u]) { dfs1(v,u,d+1); num[u]+=num[v]; if(!son[u] || num[v]>num[son[u]]) son[u]=v; } } } void dfs2(int u,int sp) { top[u]=sp; p[u]=++pos; fp[p[u]]=u; if(!son[u]) return; dfs2(son[u],sp); for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=son[u] && v!=fa[u]) dfs2(v,v); } } int queryPath(int x,int y) { int ans=0; int fx=top[x], fy=top[y]; while(fx!=fy) { if(dep[fx]>=dep[fy]) { ans+=query(p[fx],p[x],root); x=fa[fx]; } else { ans+=query(p[fy],p[y],root); y=fa[fy]; } fx=top[x], fy=top[y]; } if(x==y) return ans; if(dep[x]>dep[y]) swap(x,y); return ans+query(p[son[x]],p[y],root); } // --------------------以上是树链剖分------------------------- void initQTree() { dfs1(1,0,0); dfs2(1,1); build(root); } }T; int E[maxn][3]; int main() { while(~scanf("%d%d%d",&n,&q,&s)) { T.init(); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); E[i][0]=u, E[i][1]=v, E[i][2]=w; T.add(u,v); T.add(v,u); } T.initQTree(); for(int i=1;i<n;i++) { if(T.dep[E[i][0]]>T.dep[E[i][1]]) swap(E[i][0],E[i][1]); T.update(T.p[E[i][1]],E[i][2],root); } while(q--) { int op; scanf("%d",&op); if(op) { int k,w; scanf("%d%d",&k,&w); T.update(T.p[E[k][1]],w,root); } else { int v; scanf("%d",&v); printf("%d ",T.queryPath(s,v)); s=v; } } } return 0; }
以上是关于修改图中的边权的主要内容,如果未能解决你的问题,请参考以下文章