【每日一题】城市网络 (倍增)

城市网络

https://ac.nowcoder.com/acm/problem/13331

题意:给你以1为根的树,问u到v有多少个节点,权值严格大于路径上所有节点的权值和w。保证v在u到根节点的路径上。
首先我们考虑普通的解法,对于每一次询问,dfs从u节点到v节点,保存前缀最大值,那么当搜到的这个节点的权值大于前缀最大值时,答案加一,这样做的时间复杂度是o(nq)
code:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
vector<int>G[maxn];
int f[maxn],a[maxn];
void dfs(int u,int fa)
{
    f[u] = fa;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if(v == fa)continue;
        dfs(v,u);
    }
}
void qu(int u,int v,int w)
{
    int mx = w;
    int ans = 0;
    while(u != f[v])
    {
        if(a[u] > mx)++ans;
        mx = max(mx,a[u]);
        u = f[u];
    }
    printf("%d\n",ans);
}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].pb(v);
        G[v].pb(u);
    }
    dfs(1,0);
    while(q--)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        qu(u,v,w);
    }
}

如何优化?倍增。f[i][j]代表的是从i节点往上严格比她大的第2^j个元素的编号,那么f[u][i] = f[f[u][i-1]][i-1]。关键是如何求出f[u][0]?因为f[fa][0-logn]都先于u求出来了,那么如果a[fa] > a[u]的话,f[u][0] = fa;否则就以fa为起点倍增求出第一个大于a[u]的元素编号赋给f[u][0],这样的时间复杂度时o(qlogn)。
code:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 2e5+100;
int a[maxn],d[maxn];
vector<int>G[maxn];

int f[maxn][20],dep[maxn];
void dfs(int u,int fa,int ds)
{
    dep[u] = ds;
    int tt = fa;
    if(a[fa] > a[u])
        f[u][0] = fa;
    else
    {
        for(int i=19;~i;i--)
            if(f[fa][i] && a[f[fa][i]] <= a[u])fa = f[fa][i];
        f[u][0] = f[fa][0];
    }
    for(int i=1;i<20;i++)f[u][i] = f[f[u][i-1]][i-1];
    for(int i=0;i<G[u].size();i++)
    {
        if(G[u][i] == tt)continue;
        dfs(G[u][i],u,ds+1);
    }
}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d",a+i);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].pb(v);
        G[v].pb(u);
    }
    for(int i=1;i<=q;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        G[i+n].pb(u);
        G[u].pb(i+n);
        d[i] = v,a[i+n] = w;
    }
    dfs(1,0,1);
    for(int i=1;i<=q;i++)
    {
        int u = n+i,v = d[i],ans=0;
        for(int i=19;~i;i--)
            if(dep[f[u][i]] >= dep[v])u = f[u][i],ans+=1<<i;
        printf("%d\n",ans);
    }
}
全部评论

相关推荐

原来已经一年了,因为没有加任何实验室没有学长学姐带,再一次偶然的机会下刷到我们学校的牛肉哥,和他聊天之后发现他也没加实验室能进大厂,我就燃起了希望,去年大概&nbsp;4&nbsp;月份找好路线&nbsp;零基础&nbsp;开始学&nbsp;5&nbsp;月背八股和开始刷算法很难受&nbsp;7-8&nbsp;月焦虑躯体化害怕找不到实习&nbsp;9&nbsp;月找到一家像样的小厂去实习了&nbsp;4&nbsp;个月大三上期末考试结束之后&nbsp;1&nbsp;月份回来边实习边准备工作压力很大&nbsp;当时只有字节、百度、商汤的面试,字节三面挂了,百度&nbsp;oc,商汤&nbsp;二面挂(差评&nbsp;无效面试),之后来深圳百度实习之后还是觉得不甘心一直没把算法和八股扔下一直在准备,百度实习的时候&nbsp;mt&nbsp;交给我一个特别重要的工作数据库迁移(特别感谢&nbsp;mt&nbsp;,这个需求学到了很多东西处理了一堆线上问题),本来看着暑期他们面试都很困难,然后听说百度要涨实习薪资(然而&nbsp;5&nbsp;月并没有涨),就想着留在百度吧也懒得面试了,4&nbsp;月&nbsp;20&nbsp;多的时候字节&nbsp;hr&nbsp;打电话约面问我要不要尝试一下询问了&nbsp;1&nbsp;月份三面为啥会挂有没有学习&nbsp;ai&nbsp;知识(因为字节这边后端岗位偏&nbsp;ai),我来到百度之后全面拥抱&nbsp;AI&nbsp;也认识了我的好兄弟&nbsp;X&nbsp;哥,他在百度&nbsp;XX&nbsp;部门&nbsp;Agent&nbsp;实习,他属于是我&nbsp;Agent&nbsp;的启蒙老师,来百度之后一直在了解&nbsp;AI&nbsp;这一块,我就接受了字节的面试,一面的时候&nbsp;20&nbsp;分钟实习拷打然后突然说&nbsp;30&nbsp;分钟代码考核我心就凉了以为是&nbsp;kpi,算法题是手撕高并发安全下的令牌桶限流器,我写了整整&nbsp;80&nbsp;多行代码最后也写出来了,但是从来没看到过出这种题能&nbsp;oc&nbsp;的我也就不管了,后边面试也是很顺利但是流程有点长可能一直在横向吧总结结果是好的!!!感谢这一年努力的自己和遇到的各位互联网大佬分享的知识!!!ps&nbsp;图二纯感慨&nbsp;(觉得🍬请不要喷我)欢迎大家一起交流学习呀!!!!
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务