机房测试3:ZGY的早餐(Floyd+倍增)

题目:

分析:

由数据范围可知:前五个点是Floyd,后五个点是一颗树,两两点之间的路径是唯一的,只需要求lca即可。

Floyd注意实现细节:

1.初始化时要把dis[i][i]赋成0

2.只有1个dis数组

倍增注意:

统计答案的时候要先统计在跳fa!!

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1005
#define nn 100005
#define M 250005
#define ri register int
const ll inf=1ll<<60;
int f[nn][22],nex[M<<1],head[nn],to[M<<1],tot=0,dep[nn],n,m;
ll sum[nn][22],ww[M<<1];
int read()
{
    int x=0,fl=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) fl=-1; ch=getchar(); }
    while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x*fl;
}
ll dis[N][N];
void work1()
{
    ll a,b,c;
    for(ri i=1;i<=n;++i){
        for(ri j=1;j<=n;++j)
        if(i!=j) dis[i][j]=inf;
    }
    for(ri i=1;i<=m;++i) a=read(),b=read(),c=read(),dis[a][b]=min(dis[a][b],c),dis[b][a]=min(dis[b][a],c);
    for(ri k=1;k<=n;++k)
     for(ri i=1;i<=n;++i)
      for(ri j=1;j<=n;++j)
       if(dis[i][k]+dis[k][j]<dis[i][j])
        dis[i][j]=dis[i][k]+dis[k][j],dis[j][i]=dis[i][j];
    int Q=read();
    while(Q--){
        int s=read(), h=read(), t=read();
        printf("%lld\n",dis[s][h]+dis[h][t]);
    }
}
void add(int a,int b,int c)
{
    to[++tot]=b; nex[tot]=head[a]; head[a]=tot; ww[tot]=c;
    to[++tot]=a; nex[tot]=head[b]; head[b]=tot; ww[tot]=c;
}
void dfs(int u,int fa)
{
    for(ri i=head[u];i;i=nex[i]){
        int v=to[i];
        if(v==fa) continue;
        dep[v]=dep[u]+1;
        f[v][0]=u; sum[v][0]=ww[i];
        for(ri j=1;j<=20;++j) f[v][j]=f[f[v][j-1]][j-1];
        for(ri j=1;j<=20;++j) sum[v][j]=sum[f[v][j-1]][j-1]+sum[v][j-1];
        dfs(v,u);
    }
}
ll query(int a,int b)
{
    ll summ=0;
    if(dep[a]<dep[b]) swap(a,b);
    for(ri i=20;i>=0;--i)
    if(dep[f[a][i]]>=dep[b]) summ+=sum[a][i],a=f[a][i];//!!!
    if(a==b) return summ;//
    for(ri i=20;i>=0;--i)
    if(f[a][i]!=f[b][i])
     summ+=sum[a][i]+sum[b][i], a=f[a][i], b=f[b][i];
    return summ+sum[a][0]+sum[b][0];
}
void work2()
{
    int a,b,c;
    for(ri i=1;i<=m;++i) a=read(),b=read(),c=read(),add(a,b,c);
    dfs(1,0);
    int Q=read();
    while(Q--){
        int s=read(), h=read(), t=read();
        printf("%lld\n",query(s,h)+query(h,t));//
    }/**/
}
int main()
{
    freopen("mindis.in","r",stdin);
    freopen("mindis.out","w",stdout);
    int T=read(); n=read(), m=read() ;
    if(T<=6) work1();
    else work2();
}
/*
0 5 5
1 2 1
2 3 1
3 4 2
4 5 1
2 5 1
2
1 4 5
5 4 5

0 5 6
1 2 3
2 3 4
2 4 2
1 3 2
3 5 4
4 5 5
2
1 3 5
1 2 5

7 6 5
1 2 100000000
1 3 500000000
2 5 400000000
2 4 300000000
4 6 200000000
3
4 5 3
6 2 1
6 1 3
*/

原文地址:https://www.cnblogs.com/mowanying/p/11623357.html

时间: 2024-10-07 00:06:01

机房测试3:ZGY的早餐(Floyd+倍增)的相关文章

[20191004机房测试] ZGY的早餐

ZGY 每天早上要从宿舍走路到机房,顺便从学校小卖部购买早饭,当然机智的 ZGY 一定会走最短路 学校的路可以看成一无向联通张图,图上有 n 个点,m 条边,每一个点都有一个唯一的编号 1~n 每一条边有一个边权,表示两个点之间的距离,ZGY 的宿舍在 S 点,机房在 T点,而小卖部在 H 点 现在 ZGY 想知道从宿舍经过小卖部到达机房的最短距离 不过因为在这个世界上有 Q个 ZGY,所以你必须回答 Q 个问题 很棒的数据分治题 读入里面说了会读入测试点编号-- 其实是很明显的暗示了-- 一半

Host1Plus主机商8个机房测试IP体验

Host1Plus商家也算是比较老的海外主机商(英国),当初进入中国市场也是比较早的,记得那时候支持支付宝的海外主机商尤其的深受用户喜欢.因为我 们大部分网友.站长最多有一个支付宝,很少有双币信用卡或者贝宝支付美元的能力.不过后来几年,HOST1PLUS商家逐渐的落寞,主要原因在于其他商家 的出现,以及他们本身营销能力和产品的策略. 尤其是提供的虚拟主机和VPS主机,价格和方案不是太符合中国用户的口味,配置比较低,而且机房较 少.不过商家应该意识到这一点,在最近2年改动挺大的,今天公司业务正好有

(floyd 倍增) poj 3613

Cow Relays Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5720   Accepted: 2266 Description For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout

(floyd倍增) poj 3613

Cow Relays Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5651   Accepted: 2230 Description For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout

POJ 3613Cow Relays( floyd 倍增法)

题意:从s点出发到达e点且n条边的最短路是多少(可以走重复的路径) 图中点<=200,n<=1000,000 思路:folyd可以实现向路径中添边,但是这题与普通的求最短路问题不一样,比如从S到E经过X条边后就已经达到了最短路,这个时候仍然要强制用folyd再添边,尽管添边后就不是最短路了,但是要注意到添加的这边要使最短路损失最小,抓住这点用folyd可以实现强制添边的操作,所以可以从n=1的状态向n的状态转移 所以可以对原来的map进行n-1次folyd,但是n的范围太大,最坏的情况要进行1

机房测试9.22

题解之前 中秋只有一天假! build 以为并查集水题,发现有历史版本,于是可持久化并查集一波(爆0了) 其实有简单点的做法:用二元组记录每一次变化的siz和fa,二分查询即可. 我还在肝可持久并查集,所以就没有代码了. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; co

机房测试9.23

题解之前 今天还行啊. Set 肯定要取模. 开始还在想vector这种操作,后来一个dalao发现一定有解,然后有发现一定有一种答案是连续的一段区间,于是就切掉了. 看了题解才发现我们只是运气好. 前缀和如果有n取值,就选%n=0的那一个,不然至多只剩n-1个取值,然而又有n个前缀和. 所以必然有两个相等,输出这之间的下标即可. #include<cstdio> #include<cctype> #include<cstring> #define FN "s

机房测试10.6

砖块 很简单的水题,写起来也很简单. 模拟写的很短,是否也是码力的体现? #include<cstdio> #include<cstring> #include<map> #define FN "block" int mp[1105][1105],dao,ans; char s[105]; int x,y,dx[4]={0,0,-1,1},dy[4]={1,-1,0,0}; std::map<char,int> m; void init(

[机房测试]数字谜题

小 X 同学有很强的计算能力,现在他正在玩一个游戏. 现在有一个正整数 x,每次操作他会将当前的数变为这个数写成二进制后 1 的个数 小 X 不断的进行操作,直到这个数变成 1 为止 由于小 X 的计算能力很强,他现在给出一 n 他想知道有多少不超过 n 的正整数会在 k 次操作后变成 1 由于答案可能很大,请对 1000000007 取模 因为数据范围是\(2^{1000}\),所以一次操作后最多就只有1000个1了 因此直接暴力处理出1~1000所有数变为1的操作次数,把次数为 \(k-1\