首页 > 其他分享 >题解 CF1051F【The Shortest Statement】

题解 CF1051F【The Shortest Statement】

时间:2022-11-13 11:36:05浏览次数:54  
标签:10 cnt int 题解 head graph Statement siz Shortest

problem

连通图,无自环,无重边,\(m-n\leq 20\),\(n\leq 10^5\),\(10^5\) 询问两点之间最短路。

solution

搞出任意一棵生成树。一共 \(21\) 条非树边。

对于任意一条路径,它只有如下 \(22\) 种情况:

  • 不经过非树边。
  • 经过第 \(i\) 条非树边(\(1\leq i\leq 21\))。

这里我们不用枚举非树边的子集之类的东西,一是不好做,二是这是最优性问题,每个元素的方案的并就是全集。

对于不经过非树边的,【模板】树上两点带权距离。

对于经过一条非树边的,从边的一端开始跑最短路即可。

最后的答案为以上 \(22\) 种情况的 \(\min\)。复杂度 \(O(mk\log m+q(\log n+k))\) 其中 \(k=m-n\)。

code

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
template<int N> struct dsu{
	int fa[N+10],siz[N+10],cnt;
	dsu(int n=N):cnt(n){for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1;}
	int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
	void merge(int x,int y){if(x=find(x),y=find(y),x!=y) cnt--,siz[x]<siz[y]&&(swap(x,y),0),siz[fa[y]=x]+=siz[y];}
};
template<int N,int M,class T=int> struct graph{
    int head[N+10],nxt[M*2+10],cnt;
    struct edge{
        int u,v;T w;
        edge(int u=0,int v=0,T w=0):u(u),v(v),w(w){}
    } e[M*2+10];
    graph(){memset(head,cnt=0,sizeof head);}
    edge&operator[](int i){return e[i];}
    int add(int u,int v,T w=0){return e[++cnt]=edge(u,v,w),nxt[cnt]=head[u],head[u]=cnt;}
    int link(int u,int v,T w=0){return add(u,v,w),add(v,u,w);}
};
template<int N,int M,class T=int> struct shortway: public graph<N,M,T>{
    graph<N,M,T> &g=*this;
	bool vis[N+10];
	void dijkstra(int s,LL dis[]){
		memset(vis,0,sizeof vis);
		priority_queue<pair<LL,int>,vector<pair<LL,int>>,greater<pair<LL,int>>> q;
		for(q.push({dis[s]=0,s});!q.empty();){
			int u=q.top().second; q.pop();
			if(vis[u]) continue; else vis[u]=1;
			for(int i=g.head[u];i;i=g.nxt[i]){
				int v=g[i].v;
				if(dis[v]>dis[u]+g[i].w) q.push({dis[v]=dis[u]+g[i].w,v});
			}
		}
	}
};
template<int N,int M,class T=int> struct treecut: public graph<N,M,T>{
    graph<N,M,T> &g=*this;
    int fa[N+10],dep[N+10],son[N+10],siz[N+10],
        dfn[N+10],rnk[N+10],top[N+10],cnt;
    treecut(){memset(son,cnt=siz[0]=0,sizeof son);}
    void dfs(int u,int f=0){
        dep[u]=dep[fa[u]=f]+1,siz[u]=1;
        for(int i=g.head[u];i;i=g.nxt[i]){
            int v=g[i].v; if(v==fa[u]) continue;
            dfs(v,u),siz[u]+=siz[v];
            if(siz[son[u]]<siz[v]) son[u]=v;
        }
    }
    void cut(int u,int topf){
        top[rnk[dfn[u]=++cnt]=u]=topf;
        if(son[u]) cut(son[u],topf);
        for(int i=g.head[u];i;i=g.nxt[i]){
            int v=g[i].v; if(v==fa[u]||v==son[u]) continue;
            cut(v,v);
        }
    }
    int lca(int u,int v){
        for(;top[u]!=top[v];u=fa[top[u]]) if(dep[top[u]]<dep[top[v]]) swap(u,v);
        if(dep[u]<dep[v]) swap(u,v); return v;
    }
};
int n,m,q,pos[30],cnt;
LL dis[30][100010],sum[100010];
shortway<100010,100100> g;
treecut<100010,100010> t;
dsu<100010> s;
void dfs(int u){for(int i=t.head[u];i;i=t.nxt[i]) if(t[i].v!=t.fa[u]) sum[g[i].v]=sum[u]+g[i].w,dfs(t[i].v);}
int main(){
//	#ifdef LOCAL
//	 	freopen("input.in","r",stdin);
//	#endif
	scanf("%d%d",&n,&m);
	for(int i=1,u,v,w;i<=m;i++){
		scanf("%d%d%d",&u,&v,&w);
		pos[++cnt]=g.link(u,v,w);
		if(s.find(u)!=s.find(v)) cnt--,t.link(u,v,w),s.merge(u,v);
	}
	memset(dis,0x3f,sizeof dis);
	for(int i=1;i<=cnt;i++) g.dijkstra(g[pos[i]].u,dis[i]);
	t.dfs(1),t.cut(1,1),dfs(1);
	scanf("%d",&q);
	for(int i=1,u,v;i<=q;i++){
		scanf("%d%d",&u,&v);
		LL ans=sum[u]+sum[v]-2*sum[t.lca(u,v)];
		for(int j=1;j<=cnt;j++) ans=min(ans,dis[j][u]+dis[j][v]);
		printf("%lld\n",ans);
	}
	return 0;
}  

标签:10,cnt,int,题解,head,graph,Statement,siz,Shortest
From: https://www.cnblogs.com/caijianhong/p/solution-CF1051F.html

相关文章

  • ABC277E 题解
    前言题目传送门!更好的阅读体验?非常套路的分层图,纪念赛时切掉了。思路我们以样例来解释。首先,这是最基础的图。我们把图分成两层:第一层是原本\(w=1\)的路可以通......
  • ABC277D 题解
    前言题目传送门!或许更好的阅读体验?比较简单的模拟。思路首先把\(a_i\)排序。每次往后一直跑,如果不能再取了,就停下。但是这样做是\(O(n^2)\)的。我们需要优化。......
  • EasyExcel低版本中数据行中包含空数据会跳过导致数据对应不上的问题解析
    文章摘自:https://blog.csdn.net/caijwjava/article/details/100855361实战1、导入一个相关依赖即可<dependency><groupId>com.alibaba</groupId><artifactId>easyexc......
  • SOJ1680 题解
    昨天比赛的T3,题解思路比较新颖,小记一下。题意网格图上,人物要从\((0,0)\)走到\((n,m)\)。给出两个长度分别为\(n,m\)的序列\(a,b\),若\(a_i+b_j>0\),则\((i,j)\)......
  • 洛谷P8849 『JROI-7』hibernal 二分法题解
    题目链接题目大意:交互题,给定N=2或18或64或512或1000,其中你要通过19次以内的询问在数列1-N中找到给定的未知的两个数x和y(本题解中设x<y),每次询问......
  • 题解:【JROI-7】hibernal
    题目链接交互题,显然返回值为\(1\)时在所分的两个组中各一个,否则则在所分的同一个组中。限制次数的题一般都从数据范围入手,可以发现最大范围\(log_21000\approx9\),再......
  • uView list 控件分页加载出现抖动问题解决方案
    使用u-list 组件 动态加载数据时 滑动列表元素 会出现抖动的情况解决 设置preLoadScreen为根据page的动态变换就可以了preLoadScreen 列表前后预渲染的屏数,1......
  • AtCoder Beginner Contest 277 题解
    掉大分力(悲A-^{-1}直接模拟。#include<bits/stdc++.h>#defineIOSios::sync_with_stdio(false)#defineTIEcin.tie(0),cout.tie(0)#defineintlonglongusing......
  • CSP-J2022 题解
    一、乘方\(\text{pow}\)洛谷题面我们看数据范围:对于\(100\%\)的数据,保证\(1\lea,b\le10^9\)可以轻易得知,即使没有别的限制,至少也应该用快速幂解决而这题只......
  • 洛谷P5309 Ynoi 2011 初始化 题解
    题面。我也想过根号分治,但是题目刷得少,数组不敢开,所以还是看题解做的。这道题目要用到根号分治的思想,可以看看这道题目和我的题解。题目要求处理一个数组a,支持如下操作......