The 18th Zhejiang Provincial Collegiate Programming Contest

本文探讨了在特定树状结构中求解最短路径问题的高效算法,并通过实例解析了一个涉及逻辑判断的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. Shortest Path Query(最短路)

类似二叉树的一个结构,考虑对每个点暴力其子树内的点跑最短路,

则每个点只会被祖先的logn个点遍历一遍,总点数是O(n(logn)^2)的

对于u、v来说,答案类似询问u、v的lca,枚举lca检查到u、v的最小值和即可

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<ll,int> P;
#define pb push_back
#define fi first
#define se second
const int N=1e5+10;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int s,t,n,m,Q,u,v,w,bit[N];
ll dis[N][18];
vector<P>e[N];
bool vis[N][18];
int main(){
    memset(dis,INF,sizeof dis);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        bit[i]=bit[i>>1]+1;
    }
    for(int i=1;i<=m;++i){
        scanf("%d%d%d",&u,&v,&w);
        e[u].pb(P(v,w));
        e[v].pb(P(u,w));
    }
    for(int i=1;i<=n;++i){
        priority_queue<P>q;
        dis[i][0]=0;
        q.push(P(0,i));
        while(!q.empty()){
            int x=q.top().first,u=q.top().second;q.pop();
            int dep=0;
            for(int y=u;y!=i;y/=2)dep++;
            if(vis[u][dep])continue;
            vis[u][dep]=1;
            for(int j=0;j<e[u].size();++j){
                int v=e[u][j].first,w=e[u][j].second,nex=0;
                if(v>=i){
                    for(int y=v;y!=i;y/=2)nex++;
                    if(dis[v][nex]>dis[u][dep]+w){
                        dis[v][nex]=dis[u][dep]+w;
                        q.push(P(-dis[v][nex],v));
                    }
                }
            }
        }
    }
    scanf("%d",&Q);
    while(Q--){
        scanf("%d%d",&s,&t);
        ll now=2*INF;
        int ts=s,tt=t,nt=0,ns=0;
        if(bit[ts]>bit[tt])swap(ts,tt),swap(s,t);
        while(bit[tt]>bit[ts])tt/=2,nt++;
        while(tt!=ts){
            tt/=2,ts/=2;
            nt++,ns++;
        }
        while(1){
            now=min(now,dis[s][ns]+dis[t][nt]);
            if(ts==1)break;
            tt/=2,ts/=2;
            nt++,ns++;
        }
        printf("%lld\n",now>=INF?-1:now);
    }
    return 0;
}

I. Grammy and Ropes(思维题)

给你三个绳结,告诉六个蓝色的点处,是否编号大的圆在上(输入为6个true、false)

回答存在多少种不同的方案,使得3个环不存在两个绳结套在一起的情况

 

如果A在B上,B在C上,C在A上,三个圆会卡在一起,这个时候必须拆开至少一个绳结,7种方案

否则三者如果没出现两两套在一起的情况,说明8种方案都可;再否则,建图暴力删点来判断

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
#define pb push_back
char s[6][15];
bool ok[6],del[3];
int a[3][3],on[3][3],res,cnt;
vector<int>e[3];
void add(int u,int v){
    a[u][v]=a[v][u]=1;
    cnt++;
}
int main(){
    for(int i=0;i<6;++i){
        scanf("%s",s[i]);
        ok[i]=(strcmp(s[i],"true")==0);
    }
    if(ok[0]^ok[3])add(0,1);
    if(ok[1]^ok[4])add(0,2);
    if(ok[2]^ok[5])add(1,2);
    if(!cnt){
        int c=0;
        for(int i=0;i<3;++i){
            for(int j=i+1;j<3;++j){
                if(!ok[c])on[j][i]=1;
                else on[i][j]=1;
                c++;
            }
        }
        bool cyc=0;
        for(int i=0;i<3;++i){
            for(int j=0;j<3;++j){
                for(int k=0;k<3;++k){
                    if(i!=j && i!=k && j!=k && on[i][j] && on[j][k] && on[k][i]){
                        cyc=1;
                    }
                }
            }
        }
        printf("%d\n",cyc?7:8);
        return 0;
    }
    for(int i=1;i<8;++i){
        for(int j=0;j<3;++j){
            del[j]=i>>j&1;
        }
        bool ans=1;
        for(int j=0;j<3;++j){
            for(int k=j+1;k<3;++k){
                if(!del[j] && !del[k] && a[j][k])ans=0;
            }
        }
        res+=ans;
    }
    printf("%d\n",res);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值