《【每日一题】3月31日 城市网络》 倍增法

城市网络

http://www.nowcoder.com/questionTerminal/339fee670055486ca7967c53bab7622f

题目相信大家都看的懂
思路:
我们从几个点入手,剖析出这题的解题思路。
首先这是个树状网络,那么我们肯定可以从树的思路入手。
然后很重要的一点,,保证 v 在 u 前往首都的最短路径上。
那么很明显,v就是在u和根节点的路径上的一点。
那么就可以归到求LCA的问题了。
普通的往上跑,那么这题的数据范围会超时,所以我们用倍增来跳。
如何倍增?这题的一个限制条件就是珠宝大时才能买,如果小就相当于不存在。
所以我们就只向上去连大的珠宝点。
所以我们设置dp[i][j]表示节点i,向上购买到2^j个珠宝点时的节点.
那么从这里我们可见,我们的倍增连接应该是通过节点的珠宝价值来连接,而不是单纯的连接深度。
那我们就可以知道dp[i][0]就是节点i向上购入1(即2^0)个节点时的位置。
dp[i][1]就是节点i向上购入2(即2^1)个节点时的位置。
dp[i][2]就是节点i向上购入4(即2^2)个节点时的位置。
....
然后关于查询的处理,我们将查询的那个点的珠宝价值变成一个新的点,连入出发点u。
那么我们就可以用每个连入的查询点来进行我们的查询操作了。

Code:
#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<math.h>
#include<stack>
#include<map>
#include<limits.h>
#include<vector>
#include<string.h>
#include<string>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5+5;
const int M = 1e6+5;
#define pi acos(-1)
#define INF 1e8
#define INM INT_MIN
#define pb(a)  push_back(a)
#define mk(a,b) make_pair(a,b)
#define dbg(x) cout << "now this num is " << x << endl;
#define met0(axx) memset(axx,0,sizeof(axx));
#define metf(axx) memset(axx,-1,sizeof(axx));
#define sd(ax) scanf("%d",&ax)
#define sld(ax) scanf("%lld",&ax)
#define sldd(ax,bx) scanf("%lld %lld",&ax,&bx)
#define sdd(ax,bx) scanf("%d %d",&ax,&bx)
#define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx)
#define sfd(ax) scanf("%lf",&ax)
#define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx)
#define pr(a) printf("%d\n",a)
#define plr(a) printf("%lld\n",a)
int a[N],deep[N],fa[N];//deep记录节点深度.fa记录的是我们接入的查询节点,方便后面倍增
vector<int> G[N];
int dp[N][21];
/*
dp记录的是,向上走的购买位置.
就是说dp[i][0]是dp上面的第一个比他珠宝数大的点。然后dp[i][1]就是第二个.
dp[i][2]就是第四个..以此类推.
*/
void dfs(int u,int fa)
{
    deep[u] = deep[fa]+1;
    if(a[fa] > a[u]) dp[u][0] = fa;
    else
    {
        int x = fa;
        for(int i=20;i>=0;--i) if(a[dp[x][i]] <= a[u] && dp[x][i] != 0) x = dp[x][i];//通过父节点往上跳.倍增试探
        dp[u][0] = dp[x][0];//如果上面的所有点都是比u的值小,那么dp[u][0]就是根节点的祖先
    } 
    for(int i=1;i<=20;++i)//倍增递推,因为根节点已经处理好了,那么i就可以从1开始了
    {
        dp[u][i] = dp[dp[u][i-1]][i-1];
    }
    for(int i=0;i<G[u].size();++i)
    {
        int y = G[u][i];
        if(y == fa) continue;
        dfs(y,u);
    }
}
int main()
{
    int n,q;sdd(n,q);
    for(int i=1;i<=n;++i) sd(a[i]);
    for(int i=1;i<n;++i)
    {
        int x,y;sdd(x,y);
        G[x].pb(y),G[y].pb(x);
    }
    for(int i=1;i<=q;++i)
    {
        int x,y,z;sddd(x,y,z);
        G[x].pb(i+n);
        a[i+n] = z;
        fa[i+n] = y;
    }
    dfs(1,0);
    for(int i=1;i<=q;++i)
    {
        int u = i+n,v = fa[i+n],ans = 0;
        for(int j=20;j>=0;--j)
        {
            if(deep[dp[u][j]] >= deep[v])//当前要跳去的节点深度比我们终点大,那么就可以跳去,因为还在它下面 
            {
                ans += (1<<j);
                u = dp[u][j];
            }
        }
        pr(ans);
    }
    system("pause");
    return 0;
}
全部评论

相关推荐

10-27 17:26
东北大学 Java
点赞 评论 收藏
分享
评论
1
收藏
分享
牛客网
牛客企业服务