首页 > 其他分享 >洛谷 P6573 [BalticOI 2017] Toll 题解

洛谷 P6573 [BalticOI 2017] Toll 题解

时间:2022-11-01 16:36:24浏览次数:66  
标签:cnt 洛谷 Matrix int 题解 head edge BalticOI define

Link

算是回归OI后第一道自己写的题(考CSP的时候可没回归)

写篇题解纪念一下


题目大意: \(n\) 个点,\(m\) 条单向边,每条边的两端点 \(x\),\(y\)必定满足 \(\left\lfloor\dfrac{y}{k}\right\rfloor=\left\lfloor\dfrac{x}{k}\right\rfloor+1\), \(q\)次询问,求每一对\(a\),\(b\)的最短距离。

\(n<=5*10^{4},q<=10^4\)\(1<k<5\),保证\(a\)<\(b\)

简单分析一下容易发现这是个分层图,每 \(k\) 个点为一层,只有相邻的层间有边且边只能往编号大的方向去。

然后就是考虑这个东西怎么维护了,考虑前两天CSP2022的T4做法之一,矩阵乘法+倍增优化dp

容易发现我们可以把每个层缩成一个点,之后的图就成了好多条链(注意不一定保证联通)

然后对于这条链中的每两个相邻节点(即相邻两层),我们可以用类似Floyd的方法把原图中的边构造一个矩阵,接着就可以矩阵乘法快速合并了。

然后再倍增处理一下就结束了

记得判连通性。

(我自己的实现把链当成树了所以看起来有些麻烦。。。但是问题不大,能过就行)

点击查看代码
#include <bits/stdc++.h>
#define N 50010
#define M 1000010
#define pii pair<int,int>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
//#define int long long
//#define MOD
#define INF 1000000000
#define int_edge int to[M],nxt[M],head[N],cnt=0;
using namespace std;
int k,n,m,q,fa[N][16],f[N],dep[N],eid=0,vis[N];
int_edge;void add_edge(int x,int y ){to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
map<pii,int>mp;
struct Y{int x,y,t;};vector<Y>E[N];
int id(int x){return x/k+1;}
//int_edge;int val[M];void add_edge(int x,int y,int z){to[++cnt]=y;val[cnt]=z;nxt[cnt]=head[x];head[x]=cnt;}
struct Matrix{
	int a[5][5];
	Matrix(){memset(a,0x3f,sizeof(a));}
	Matrix operator * (const Matrix &y){
		Matrix sum;
		for(int i=0;i<5;i++)
			for(int j=0;j<5;j++)
				for(int k=0;k<5;k++)
					sum.a[i][j]=min(sum.a[i][j],a[i][k]+y.a[k][j]);
		return sum;
	}
}dn[N][16];
Matrix init(){
	Matrix x;for(int i=0;i<k;i++)x.a[i][i]=0;return x;
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs(int nw,int lst){
	vis[nw]=1;
	fa[nw][0]=lst;dep[nw]=dep[lst]+1;
	if(lst!=0){
		for(auto e:E[mp[mkp(lst,nw)]]){
			dn[nw][0].a[e.x%k][e.y%k]=e.t;
		}
	}
	for(int i=1;i<=15;i++){
		fa[nw][i]=fa[fa[nw][i-1]][i-1];
		dn[nw][i]=dn[fa[nw][i-1]][i-1]*dn[nw][i-1];
	}
	for(int i=head[nw];i;i=nxt[i])
		if(to[i]!=lst)dfs(to[i],nw);
}
signed main()
{
	scanf("%d %d %d %d",&k,&n,&m,&q);
	for(int i=0;i<n;i++)f[i]=i;
	for(int i=1,x,y,t;i<=m;i++){
		scanf("%d %d %d",&x,&y,&t);
		f[find(x)]=find(y);
		if(mp.find(mkp(id(x),id(y)))==mp.end()){
			mp[mkp(id(x),id(y))]=++eid;
			add_edge(id(x),id(y));
		}
		E[mp[mkp(id(x),id(y))]].pb(Y{x,y,t});
	}
	for(int i=1;i<=id(n);i++)if(!vis[i])dfs(i,0);
	while(q--){
		int x,y;scanf("%d %d",&x,&y);
		if(find(x)!=find(y)){puts("-1");continue;}
		int id1=id(x),id2=id(y);
		Matrix ans=init();
		for(int i=15;i>=0;i--)
			if(dep[fa[id2][i]]>=dep[id1])
				ans=dn[id2][i]*ans,id2=fa[id2][i];
		if(ans.a[x%k][y%k]==1061109567)puts("-1");
			else printf("%d\n",ans.a[x%k][y%k]);
	}
	return 0;
}



标签:cnt,洛谷,Matrix,int,题解,head,edge,BalticOI,define
From: https://www.cnblogs.com/shight/p/16848151.html

相关文章

  • DJango + Vue 跨域问题解决
    什么是跨域同源:协议+域名+端口号,三者完全相同以上三个元素只要有一个不相同就是跨域产生跨域异常的报错信息如下:accesstoxmlhttprequestat'http://ip:port1/a......
  • 洛谷P1462spfa + 二分答案
    第一次接触二分答案的题目最开始是没有思路的看了一个题解,然后强行理解之后开始自己打了一遍,然而结果是只得了30分过了3个点其他全wa,之后是漫长的debug,这里想感慨一句自己d......
  • P8819 [CSP-S 2022] 星战 题解
    思路考前练习了特别多的随机权题目,但是考场上考了我们整个机房都没做出来。通读题目,发现如果当前可以进行反攻了,只有此时的所有点的出度均为一。考虑它的四个操作。给......
  • P8818 [CSP-S 2022] 策略游戏 题解
    思路题意:求一个特定矩形中每一行的最小值的最大值。考虑分类讨论。注意,由于\(0\)也需要考虑,所以下文中的正数和负数都包括了\(0\)。\(\text{a}\)全部都是正的。......
  • 洛谷 P5369
    先规定一些东西:若存在多个\(p\)使得\(\sum_{i=1}^{p}{a_i}\)最大,默认最大(即最靠右)的一个\(p\)是它的最大前缀和的位置。\(U\)表示全集。假设\(p\)是最大前缀......
  • CSP-S 2022 T4 题解
    简述题意给一颗\(n\)个点的树,每个点有点权\(v_i\)。有\(q\)次询问,每次给出\((u,v)\),从\(u\)开始,每步只能走不超过\(k\)条边,走一步的代价是终点的点权,\(v_u\)也......
  • SP9340 题解
    前言题目:三倍经验。SP9340、UVA346、P1931。更好的阅读体验?简单的Floyd。思路......
  • SP19568 题解
    前言题目传送门!更好的阅读体验?好的线段树练习题。思路我们要维护三个操作:单点加。区间推平。区间查询质数。区间推平可以想到珂朵莉树,但是我不会,于是考虑线段树......
  • 洛谷 P1464 Function(dfs+记忆化搜索)
    https://www.luogu.com.cn/problem/P1464单个返回条件的时候,直接return多个返回条件的时候,采用记忆化搜索思想,边存储边继续往下搜索中间穿插记忆化判断,如果之前有过此......
  • CSP-S 2022 第二轮 nt 游记 & 题解
    CSP-S2022第二轮nt游记&题解T1想了一个小时,想到了一个接近于正解的做法,但最后还是打了个暴力走了。T2第一眼以为很难的博弈论,结果线段树水题。但赛事少考虑了一......