树上被增

Solution

求树上的简单路径很明显是LCA的题目,那么:
直接预处理父节点数组和深度数组直接暴力把 u 和 v 往上提 ?那就错了。
其实题目里有保证 v 在 u 前往首都的最短路径上,所以只需要直接把 u 向上遍历就可以了。
而珠宝购入的前提是当前城市的珠宝严格大于手中的所有珠宝,所以只需要再用两个变量维护珠宝的最大值和购入次数即可。
显然在数据小的情况下以上暴力可以AC,但是数据量一大超时就必不可免了。
可以优化的过程便是 u 找 v 这个过程,那么就要用到本文第一句话的LCA。
由于出发节点的价值大的时候也会购入,所以可以处理询问的时候可以把每组询问离线,出发点作为新节点的父亲,带着的珠宝价值作为新点的点权,目标点用新的数组存终点。
设 f[u][i] 为从u节点出发要购入 2^i 次珠宝第一次到达的城市,
由于是从根节点开始dfs,所以父节点都是处理好的,
那么倍增的递推式很明显: f[u][i]= f[ f[u][i-1] ][i-1];
那么最后只要倍增使每组询问的两个点深度相同即可,步数为 f[u][i] 的 2^i 。

#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define ins insert
#define eps 1e-8
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
using namespace std;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
void put1(){ puts("YES") ;}void put2(){ puts("NO") ;}void put3(){ puts("-1"); }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a =
(a*a)%p;b >>= 1;}return ans%p;}
const ull base=2333; const ull pp=19260811; const ull ppp=999998639;

const int manx=2e5+5;
const int mo=998244353;

vector<ll>g[manx];
ll f[manx][25],a[manx],to[manx],d[manx];

void dfs(ll u,ll pre){
    ll father=pre;
    d[u]=d[pre]+1;
    for(int i=19;i>=0;i--)
        if(a[ f[pre][i] ]<=a[u]&&f[pre][i])
            pre=f[pre][i];
    if(a[pre]>a[u]) f[u][0]=pre;
    else f[u][0]=f[pre][0];
    for(int i=1;i<=19;i++)
        f[u][i]=f[ f[u][i-1] ][i-1];
    for(auto v : g[u]){
        if(v==father) continue;
        dfs(v,u);
    }
}

int main()
{
    ll n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<n;i++){
        ll u=read(),v=read();
        g[u].pb(v); g[v].pb(u);
    }
    for(int i=n+1;i<=n+m;i++){
        ll u=read(),v=read(),w=read();
        g[u].pb(i); g[i].pb(u);
        to[i]=v;  a[i]=w;
    }
    dfs(1,0);
    for(int x=n+1;x<=n+m;x++){
        ll cnt=0,u=x;
        for(int i=19;i>=0;i--){
            if(d[ f[u][i] ]>=d[ to[x] ]){
                cnt+=(1<<i);
                u=f[u][i];
            }
        }
        printf("%lld\n",cnt);
    }
    return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务