首页 > 其他分享 >CF-720-E- 最短路+最小生成树

CF-720-E- 最短路+最小生成树

时间:2024-01-17 21:44:07浏览次数:17  
标签:int 短路 CF fa vector 720 -- dis

1051-F 题目大意

给定一个\(n\)个点\(m\)条边的无向联通图,边带权。有\(q\)次询问,每次询问两点\(x,y\)直接的最短路的长度。


Solution

注意到\(m-n{\le}20\),那么整个图可以视为一个生成树加上不超过\(21\)条非树边构成的图,这些非树边构成一个边集\(E\)。

先把整个图的最小生成树搞出来。考虑两点\(x,y\)之间的最短路,分为两种:

  • 一种是不经过非树边的最短路,这里用求\(LCA\)的方法可以得出。
  • 一种是经过非树边的最短路,可以枚举边集\(E\)中的边\(e\),边\(e\)连接的两点为\(u,v\),边权为\(w\),那么点\(x,y\)经过\(e\)的最短路的长度为

\[min(dis_{u-x}+dis_{v-y},dis_{v-x}+dis_{u-y})+w \]

这就需要我们预处理出所有边集\(E\)连接的点在原图上的最短路,用\(dijkstra\)解决即可。

二者取最小值即为询问的答案,时间复杂度为\(O(mlogm+nlogn+(m-n)mlogn+q(m-n+logn))\)。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

template<typename T>
struct DSU{
	int n;
	vector<T> p,siz;
	DSU(int _n):p(_n+1),siz(_n+1),n(_n){
		iota(p.begin(),p.end(),0);
		for(int i=0;i<=n;i++) siz[i]=1;
	}
	T findd(T x){
		return p[x]==x?x:p[x]=findd(p[x]);
	}
	void unionn(T x,T y){
		x=findd(x),y=findd(y);
		if(x==y) return;
		if(siz[x]>siz[y]) swap(x,y);
		p[x]=y;
		siz[y]+=siz[x];
	}
};

void solve(){
    int n,m;
    cin>>n>>m;
    vector<array<int,3>> ed(m);
    vector<array<int,3>> other;
    for(int i=0;i<m;i++){
        int x,y,w;
        cin>>x>>y>>w;
        x--,y--;
        ed[i]={x,y,w};
    }
    sort(ed.begin(),ed.end(),[](const auto &a,const auto &b){
        return a[2]<b[2];
    });
    DSU<int> dsu(n);
    vector<vector<pair<int,int>>> g(n),e(n);
    for(int i=0;i<m;i++){
        auto [x,y,w]=ed[i];
        if(dsu.findd(x)!=dsu.findd(y)){
            dsu.unionn(x,y);
            e[x].push_back({y,w});
            e[y].push_back({x,w});
        }else{
            other.push_back(ed[i]);
        }
        g[x].push_back({y,w});
        g[y].push_back({x,w});
    }
    int P=18;
    vector<ll> pre(n);
    vector<int> dep(n);
    vector<vector<int>> fa(n,vector<int>(P));
    function<void(int,int)> dfs=[&](int x,int father){
        fa[x][0]=father;
        for(int i=1;i<P;i++){
            fa[x][i]=fa[fa[x][i-1]][i-1];
        }
        for(auto [y,w]:e[x]){
            if(y==father) continue;
            pre[y]=pre[x]+w;
            dep[y]=dep[x]+1;
            dfs(y,x);
        }
    };
    dfs(0,0);
    function<int(int,int)> lca=[&](int x,int y){
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=P-1;~i;i--){
            if(dep[fa[x][i]]>=dep[y]){
                x=fa[x][i];
            }
        }
        if(x==y) return x;
        for(int i=P-1;~i;i--){
            if(fa[x][i]!=fa[y][i]){
                x=fa[x][i],y=fa[y][i];
            }
        }
        return fa[x][0];
    };
    map<int,vector<ll>> dis;
    function<vector<ll>(int)> dijkstra=[&](int s){
        vector<ll> d(n,1e16);
        vector<int> vis(n);
        d[s]=0;
        priority_queue<pair<ll,int>,vector<pair<ll,int>>,greater<>> q;
        q.push({0,s});
        while(!q.empty()){
            auto [dx,x]=q.top();
            q.pop();
            if(vis[x]) continue;
            vis[x]=1;
            for(auto [y,w]:g[x]){
                if(!vis[y]&&d[x]+w<d[y]){
                    d[y]=d[x]+w;
                    q.push({d[y],y});
                }
            }
        }
        return d;
    };
    for(auto [x,y,w]:other){
        if(!dis.count(x)){
            dis[x]=dijkstra(x);
        }
        if(!dis.count(y)){
            dis[y]=dijkstra(y);
        }
    }
    int q;
    cin>>q;
    while(q--){
        int x,y;
        cin>>x>>y;
        x--,y--;
        ll res=pre[x]+pre[y]-2*pre[lca(x,y)];
        for(auto [u,v,w]:other){
            res=min({res,dis[u][x]+dis[v][y]+w,dis[u][y]+dis[v][x]+w});
        }
        cout<<res<<'\n';
    }
}

int main(){
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

标签:int,短路,CF,fa,vector,720,--,dis
From: https://www.cnblogs.com/fengxue-K/p/17971243

相关文章

  • CF1633A题解
    Div.7题面翻译给定\(t\)组数据。每组数据给定一个数\(n\)(\(10\len\le999\))。每次操作可以修改\(n\)任意一位上的数,将这一位上的数修改为\(0\sim9\)之间的任意数。要求使用最少的修改次数使这个数修改后是\(7\)的倍数,并且没有多余的前导\(0\)。输出修改后的数,如......
  • CF925F Parametric Circulation
    根据无源汇上下界可行流的经典求法,令\(f(t)=\sum\limits_{d_i>0}d_i-\text{maxflow}\ge0\),则\(f(t)=0\)的时候有解。根据最大流等于最小割,\(f(t)=\sum\limits_{d_i>0}d_i-\text{mincut}\)。我们考虑\(\sum\limits_{d_i>0}d_i=\sum\limits_{d_i<0}(-d_i)\),所以\(\sum\l......
  • CF1637A题解
    SortingParts题面翻译给定一个长度为n的数组a。你可以执行恰好一次操作。每次操作选择一个在[1,n-1]内的整数len,然后将数组a中长度为len的前缀和长度为n-len的后缀分别排序。请判断是否能够通过操作,使得最终的数组a不满足\foralli\in[1,n),a_i<=a(i+1)。数据范......
  • CF-702-E-倍增
    702-E题目大意\(n\)个点,每个点有一条出边,边带权。给定整数\(k\)。求从每个节点出发经过\(k\)条边的路径上所有的边权和,以及最小的边权。Solution给定的图是基环树森林,从任意一个点出发无限走下去一定会进入环内。倍增板子题,这里不详细解释什么是倍增数组,具体的可以网上自行......
  • [CF1707E] Replace
    Replace题面翻译题目描述给定一个长为\(n\)的序列\(a_1,\ldots,a_n\),其中对于任意的\(i\)满足\(1\leqa_i\leqn\)。定义一个二元组函数如下:\[f((l,r))=(\min\{a_l,\ldots,a_r\},\max\{a_l,\ldots,a_r\})(l\leqr)\]你需要回答\(q\)次询问,每次给定\((l_i,r_i)\)......
  • CNCF大使预测:2024年云原生面临倦怠、离职及云成本精简
    本文由CNCF大使EricD.Schabell撰写,预测2024年云原生领域最可能发生的3大变化,并与其对云原生可观测性领域的见解结合。 关注云原生倦怠毫无疑问,在2023年中云原生可观测性领域的头号话题是倦怠。这涉及到每一个角色,从SREs、DevOps、工程师、开发人员到管理企业内云原生......
  • 1.同余最短路
    省选模拟赛T3一小部分用到了同余最短路,发现这简单东西自己从来没学过,补一下。\(n\)个正整数,分别为\(A_1,A_2,\cdots,A_n\),求\([0,V]\)中有多少个数可以被表示为\(\sum\limits_{i=1}^{n}A_ix_i,x_i\in\mathbb{N}\)。可以完全背包,但复杂度\(O(nV)\),当\(V\)很大的时候......
  • CF1919F2 Wine Factory (Hard Version)
    题意有\(n\)个桶,每个桶里有\(a_i\)单位水。每次查询按\(1,2...,n\)的顺序进行。当操作到桶\(i\)时,先将当前桶里的水取\(b_i\)加入答案。并将当前里的水全部流向\(i+1\),最多只能流\(c_i\)单位。每次修改\(a_p,b_p,c_p\)查询答案。Sol不难想到建模网络流......
  • CF1876D Lexichromatography 题解
    Problem-D-CodeforcesLexichromatography-洛谷先注意读题:对于所有的值\(k\),在这个序列的任意子区间\([l,r]\)中,值为\(k\)且为红色的位置数减去值为\(k\)且为蓝色的位置数的绝对值不超过\(1\)注意是任意子区间这说明什么?说明如果只有第二个条件,我......
  • CF607E Cross Sum
    首先考虑把定点置换到原点,则直线方程变为\(y+y_0=\dfraca{1000}(x+x_0)+\dfracb{1000}\)。令\(k=\dfraca{1000},c=\dfrac{ax_0+b}{1000}-y_0\),则有\(y=kx+c\)。考虑二分答案,找到一个最小的圆,使得圆内有至少\(m\)个交点,圆的半径\(r\)就是答案。......