2025 ICPC Nanchang Invitational and Jiangxi Provincial Collegiate Programming Contest——L

补题链接

分享一下 单 l o g log log 做法 代码,本质上就是找离我左边最近的点和离我右边最近的点

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
using i128 = __int128;

constexpr int maxn = 3e5+10,inf = 1e9;
int n,Q;
vector<int> g[maxn];
int fa[maxn][20],dep[maxn];//第二维取决于n的大小
int dfn[maxn],ff[maxn],idx,ans[maxn];
void dfs(int x,int f){
    fa[x][0] = f;
    dep[x] = dep[f]+1;
    dfn[x]=++idx;
    ff[idx]=x;
    //cout<<x<<" "<<idx<<"\n";
    for(auto y:g[x]){
        if(y==f) continue;
        dfs(y,x);
    }
}
void Update(){
    for(int j = 1;j<20;++j){
        for(int i = 1;i<=n;++i){
            fa[i][j] = fa[fa[i][j-1]][j-1];
        }
    }
}
int lca(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    for(int i = 19;i>=0;--i){
        if(dep[x]-dep[y]>=(1<<i)){
            x = fa[x][i];
        }
    }
    if(x==y) return x;
    for(int i = 19;i>=0;--i){
        if(fa[x][i]!=fa[y][i]){
            x = fa[x][i],y = fa[y][i];
        }
    }
    return fa[x][0];
}

struct segtree{
    struct node{
        i64 ma;
        int nd;
    }tree[maxn<<2];
    int (*cmp)(i64 a,i64 b);
    node ept;
    void pushup(int k){
        if(cmp(tree[k<<1].ma,tree[k<<1|1].ma))tree[k] = tree[k<<1];
        else tree[k] = tree[k<<1|1];
    }
    void build(int k=1,int l=1,int r=n){
        if(l==r){
            tree[k] = ept;
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        pushup(k);
    }
    void update(int x,i64 num,int k=1,int l=1,int r=n){
        if(l==r){
            tree[k].ma = num;
            tree[k].nd = x;
            return;
        }
        int mid=l+r>>1;
        if(x<=mid)update(x,num,k<<1,l,mid);
        else update(x,num,k<<1|1,mid+1,r);
        pushup(k);
    }
    node query(int L,int R,int k=1,int l=1,int r=n){
        if(r<L||R<l)return ept;
        if(L<=l&&r<=R)return tree[k];
        int mid=l+r>>1;
        node a = query(L,R,k<<1,l,mid);
        node b = query(L,R,k<<1|1,mid+1,r);
        if(cmp(a.ma,b.ma))return a;
        else return b;
    }
}sma,smi;
int cmp1(i64 a,i64 b){return a>b;}
int cmp2(i64 a,i64 b){return a<b;}

int LCA(array<int,3> point){
    int x = lca(point[0],point[1]);
    int y = lca(point[0],point[2]);
    int z = lca(point[1],point[2]);
    if(dep[x]<dep[y]) swap(x,y);
    if(dep[x]<dep[z]) swap(x,z);
    return x;
}

void solve(){
    cin>>n>>Q;
    for(int i = 1;i<n;++i){
        int x,y;
        cin>>x>>y;
        g[x].emplace_back(y);
        g[y].emplace_back(x);
    }
    dfs(1,0);
    Update();

    vector<array<int,6>> q(Q,{{-1,-1,-1,-1,-1,-1}});
    for(int i =0;i<Q;++i){
        cin>>q[i][0]>>q[i][1]>>q[i][2];
        q[i][3]=i;
    }
    sort(q.begin(),q.end(),[&](array<int,6> &x,array<int,6>&y){
        return dfn[x[2]]<dfn[y[2]];
    });
    sma.cmp = cmp1;
    sma.ept = {0,-1};
    sma.build();
    int id = 0;//dfn id
    for(int i = 0;i<Q;++i){
        while(id<dfn[q[i][2]]){
            id++;
            sma.update(ff[id],id);
        }
        q[i][5] = sma.query(q[i][0],q[i][1]).nd;
    }
    while(id<n){
        id++;
        sma.update(ff[id],id);
    }
    smi.cmp = cmp2;
    smi.ept={inf,-1};
    smi.build();
    id = n+1;
    for(int i= Q-1;i>=0;--i){
        while(id>dfn[q[i][2]]){
            id--;
            smi.update(ff[id],id);
        }
        q[i][4]=smi.query(q[i][0],q[i][1]).nd;
    }
    while(id>1){
        id--;
        smi.update(ff[id],id);
    }
    for(int i = 0;i<Q;++i){
        if(q[i][5]==-1) q[i][5] = sma.query(q[i][0],q[i][1]).nd;
        if(q[i][4]==-1) q[i][4] = smi.query(q[i][0],q[i][1]).nd;
        array<int,3> point={q[i][4],q[i][5],q[i][2]};
        ans[q[i][3]] = LCA(point);
    }

    for(int i = 0;i<Q;++i) cout<<ans[i]<<"\n";
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值