【洛谷P8820】数据传输

1|0题目


题目链接:https://www.luogu.com.cn/problem/P8820
小 C 正在设计计算机网络中的路由系统。
测试用的网络总共有 n 台主机,依次编号为 1n。这 n 台主机之间由 n1 根网线连接,第 i 条网线连接个主机 aibi。保证任意两台主机可以通过有限根网线直接或者间接地相连。受制于信息发送的功率,主机 a 能够直接将信息传输给主机 b 当且仅当两个主机在可以通过不超过 k 根网线直接或者间接的相连。
在计算机网络中,数据的传输往往需要通过若干次转发。假定小 C 需要将数据从主机 a 传输到主机 bab),则其会选择出若干台用于传输的主机 c1=a,c2,,cm1,cm=b,并按照如下规则转发:对于所有的 1i<m,主机 ci 将信息直接发送给 ci+1
每台主机处理信息都需要一定的时间,第 i 台主机处理信息需要 vi 单位的时间。数据在网络中的传输非常迅速,因此传输的时间可以忽略不计。据此,上述传输过程花费的时间为 i=1mvci
现在总共有 q 次数据发送请求,第 i 次请求会从主机 si 发送数据到主机 ti。小 C 想要知道,对于每一次请求至少需要花费多少单位时间才能完成传输。
n,Q2×105,1k3

2|0思路


下文 m 即为题目中的 k
f[x][y][i][j] 表示将数据从点 x 传输到点 y,其中点 x 之前已经使用 i 条网线,y 之前已经使用 j 条网线的最小代价。
转移的话,容易发现只需要随便选取 xy 路径上的一个点 z,就有

f[x][y][i][j]=mink=0m1(f[x][z][i][k]+f[z][y][k][j])

这样预处理时间复杂度为 O(n2),单次询问时间复杂度为 O(1)。考虑如何用询问的复杂度换预处理的复杂度。
可以发现路径是可以通过拼接进行转移的,这启发我们将 xy 的路径拆分成 xLCA(x,y) 以及 LCA(x,y)y 两段。
这样的话,每一段都是祖孙关系。可以通过倍增进行优化。
f[x][y][i][j] 的定义修改一下,y 表示到 x2y 级祖先,其他不变。那么可以 O(nlogn) 预处理出这个数组。
每次询问拆分成两条路径之后,利用倍增分别求出两条路径的 dp 数组,然后拼接在一起就好。这样询问的复杂度也是 O(nlogn)
注意由于我们求出来的是 yLCA(x,y) 的答案而非 LCA(x,y)y 的答案,所以最后合并的时候需要讨论一下 LCA(x,y) 处的权值会不会算漏或算重。
嫌转移太长可以用矩阵搞一下。
时间复杂度 O(m3nlogn)

3|0代码


#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=200010,LG=18; int n,m,Q,tot,a[N],mina[N],head[N],dep[N],f[N][LG+1]; struct Matrix { ll a[3][3]; Matrix() { memset(a,0x3f,sizeof(a)); } friend Matrix operator +(Matrix a,Matrix b) { Matrix c; for (int i=0;i<m;i++) for (int j=0;j<m;j++) for (int k=0;k<m;k++) c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]); return c; } }dis[N][LG+1],d1,d2; struct edge { int next,to; }e[N*2]; void add(int from,int to) { e[++tot]=(edge){head[from],to}; head[from]=tot; } void dfs(int x,int fa) { dep[x]=dep[fa]+1; f[x][0]=fa; dis[x][0].a[0][0]=a[fa]; if (m>=2) dis[x][0].a[1][0]=a[fa],dis[x][0].a[0][1]=0; if (m>=3) dis[x][0].a[2][0]=a[fa],dis[x][0].a[1][2]=0,dis[x][0].a[2][2]=mina[x]; for (int i=1;i<=LG;i++) { f[x][i]=f[f[x][i-1]][i-1]; dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1]; } for (int i=head[x];~i;i=e[i].next) { int v=e[i].to; if (v!=fa) dfs(v,x); } } int lca(int x,int y) { if (dep[x]<dep[y]) swap(x,y); for (int i=LG;i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; if (x==y) return x; for (int i=LG;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } Matrix calc(int x,int y) { Matrix res; res.a[0][0]=0; for (int i=LG;i>=0;i--) if (dep[f[x][i]]>=dep[y]) res=res+dis[x][i],x=f[x][i]; return res; } int main() { memset(head,-1,sizeof(head)); memset(mina,0x3f,sizeof(mina)); scanf("%d%d%d",&n,&Q,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); mina[x]=min(mina[x],a[y]); mina[y]=min(mina[y],a[x]); } dfs(1,0); for (int i=1,x,y;i<=Q;i++) { scanf("%d%d",&x,&y); int p=lca(x,y); d1=calc(x,p); d2=calc(y,p); ll ans=1000000000000000000LL; for (int i=0;i<m;i++) for (int j=0;j<m;j++) if (i+j!=0 && i+j!=4) ans=min(ans,d1.a[0][i]+d2.a[0][j]); ans=min(ans,d1.a[0][0]+d2.a[0][0]-a[p]); ans=min(ans,d1.a[0][2]+d2.a[0][2]+mina[p]); printf("%lld\n",ans+a[x]+a[y]); } return 0; }

__EOF__

本文作者stoorz
本文链接https://www.cnblogs.com/stoorz/p/16875020.html
关于博主:菜死了 /fad
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   stoorz  阅读(114)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示