LibreOJ #6192. 「美团 CodeM 复赛」城市网络

本文介绍了一道名为“城市网络”的编程竞赛题目,该题要求选手通过一系列操作确定在特定路径上购买珠宝的次数。文章提供了两种解题思路,一种是40分的暴力解法,另一种是100分的倍增优化解法。

#6192. 「美团 CodeM 复赛」城市网络

内存限制:64 MiB时间限制:500 ms标准输入输出
题目类型:传统评测方式:文本比较
上传者: sqc
题目描述

有一个树状的城市网络(即 nnn 个城市由 n−1n-1n1 条道路连接的连通图),首都为 111 号城市,每个城市售卖价值为 aia_iai​​ 的珠宝。

你是一个珠宝商,现在安排有 qqq 次行程,每次行程为从 uuu 号城市前往 vvv 号城市(走最短路径),保证 vvv 在 uuu 前往首都的最短路径上。

在每次行程开始时,你手上有价值为 ccc 的珠宝(每次行程可能不同),并且每经过一个城市时(包括 uuu 和 vvv),假如那个城市中售卖的珠宝比你现在手上的每一种珠宝都要优秀(价值更高,即严格大于),那么你就会选择购入。

现在你想要对每一次行程,求出会进行多少次购买事件。

输入格式

第一行,两个正整数 n,qn , qn,q。

第二行,nnn 个正整数 aia_iai​​ 描述每个城市售卖的珠宝的价值。

接下来 n−1n-1n1 行,每行描述一条道路 x,yx , yx,y (1≤x,y≤n1 \leq x , y \leq n1x,yn),表示有一条连接 xxx 和 yyy 的道路。

接下来 qqq 行,每行描述一次行程 u,v,cu , v , cu,v,c (1≤u,v≤n1 \leq u , v \leq n1u,vn)。

输出格式

对于每次行程输出一行,为所购买次数。

样例
样例输入
5 4
3 5 1 2 4
1 2
1 3
2 4
3 5
4 2 1
4 2 2
4 2 3
5 1 5
样例输出
2
1
1
0
数据范围与提示

#include<iostream>
#include<cstdio>
#define maxn 100010
using namespace std;
int n,q,w[maxn],num,head[maxn],fa[maxn],dis[maxn],dep[maxn];
struct node{
    int to,pre;
}e[maxn*2];
void Insert(int from,int to){
    e[++num].to=to;
    e[num].pre=head[from];
    head[from]=num;
}
void dfs(int now,int father){
    dep[now]=dep[father]+1;
    fa[now]=father;
    for(int i=head[now];i;i=e[i].pre){
        int to=e[i].to;
        if(to==father)continue;
        dfs(to,now);
    }
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    int x,y,z;
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        Insert(x,y);Insert(y,x);
    }
    dfs(1,0);
    while(q--){
        scanf("%d%d%d",&x,&y,&z);
        if(dep[x]<dep[y])swap(x,y);
        int cnt=0;
        while(x!=y){
            if(w[x]>z)cnt++,z=w[x];
            x=fa[x];
        }
        if(w[y]>z)cnt++;
        printf("%d\n",cnt);
    }
}
40分 暴力
#include<iostream>
#include<cstdio>
#define maxn 200001
using namespace std;
int fa[maxn<<1][20];
int num,head[maxn<<1],val[maxn<<1];
int d[maxn<<1],dep[maxn<<1],Dec[maxn<<1];
struct node{
    int to,pre;
}e[maxn*2];
void Insert(int from,int to){
    e[++num].to=to;
    e[num].pre=head[from];
    head[from]=num;
}
void dfs(int now,int father){
    int pos=father;
    for(int i=18;i>=0;i--)
        if(fa[pos][i]&&d[fa[pos][i]]<=d[now])pos=fa[pos][i];
    if(d[pos]>d[now])fa[now][0]=pos;
    else fa[now][0]=fa[pos][0];
    for(int i=1;fa[fa[now][i-1]][i-1];i++)fa[now][i]=fa[fa[now][i-1]][i-1];
    dep[now]=dep[father]+1;
    for(int i=head[now];i;i=e[i].pre)
        if(e[i].to!=father)dfs(e[i].to,now);
}
int main(){
    freopen("Cola.txt","r",stdin);
    int n,q;
    scanf("%d%d",&n,&q);
    int x,y,z;
    for(int i=1;i<=n;i++)scanf("%d",&d[i]);
    for(int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        Insert(x,y);Insert(y,x);
    }
    int c;
    for(int i=1;i<=q;i++){
        scanf("%d%d%d",&x,&y,&z);
        Insert(n+i,x);Insert(x,n+i);
        d[n+i]=z;
        Dec[i]=y;
    }
    dfs(1,0);
    int ans,pos,t;
    for(int i=n+1;i<=n+q;i++){
        ans=0;
        pos=i;
        t=Dec[i-n];
        for(int j=18;j>=0;j--)
            if(dep[fa[pos][j]]>=dep[t])
                ans+=1<<j,pos=fa[pos][j];
        printf("%d\n",ans);
    }
}
100分 倍增

 

转载于:https://www.cnblogs.com/thmyl/p/7719205.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值