【每日一题】3月31日

城市网络

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

我们考虑一个暴力的做法:每次从这个点找到它上面的第一个比他大的点 跳过去。
但是这样显然是过不了的。我们先丢掉询问给出的那个权 每次就拿这个点上的权来跳 答案如何快速处理。
我们可以倍增: 往上找了 个答案之后的点在哪里。问题转化为处理

这个也可以利用我们前面已经求出的f来计算:观察到 随着 的递增而递增。所以我们可以用类似询问倍增的方式来做:每次枚举 比较 和当前点的权 决定跳不跳。

对于询问 题解里有一个很巧妙的做法:将每个点接在起点的下面就可以了(也可以每一次都先倍增找到第一个比它大的)

#include<bits/stdc++.h>

#define fi first
#define se second
#define U unsigned
#define P std::pair<int,int>
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

const int MAXN = 5e5 + 5;

struct Edge{
    int to,nxt;
}e[MAXN<<1];
int head[MAXN],cnt;

inline void add(int u,int v){
    e[++cnt] = (Edge){v,head[u]};head[u] = cnt;
    e[++cnt] = (Edge){u,head[v]};head[v] = cnt;
}

int n;
int a[MAXN];
int b[MAXN],dep[MAXN],f[MAXN][20];

inline void dfs(int v,int fa=0){
    int t = fa;
    ROF(i,19,0){
        if(f[t][i] && a[f[t][i]] <= a[v]) t = f[t][i];
    }
    if(a[t] > a[v]) f[v][0] = t;
    else f[v][0] = f[t][0];
    FOR(i,1,19) f[v][i] = f[f[v][i-1]][i-1];
    for(int i = head[v];i;i = e[i].nxt){
        if(e[i].to == fa) continue;
        dep[e[i].to] = dep[v] + 1;dfs(e[i].to,v);
    }
}

int main(){
    int q;scanf("%d%d",&n,&q);
    FOR(i,1,n) scanf("%d",a+i);
    FOR(i,2,n){
        int u,v;scanf("%d%d",&u,&v);add(u,v);
    }
    FOR(i,n+1,n+q){
        int u,v,w;scanf("%d%d%d",&u,&v,&w);
        add(i,u);
        a[i] = w;b[i-n] = v;
    }
    dep[1] = 1;dfs(1,0);
    FOR(i,1,q){
        int ans = 0,v = i+n;
        ROF(k,19,0){
            if(dep[f[v][k]] >= dep[b[i]]){
                ans |= (1<<k);
                v = f[v][k];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
全部评论

相关推荐

头像
03-18 09:09
Java
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务