P4092 [HEOI2016/TJOI2016] 树

题目链接:https://www.luogu.com.cn/problem/P4092

题意:

在线查询,1.节点打上标记 2.查询给定节点打上标记的最近祖先

思路:

节点和其祖先一定在一条链上,所以转化为树链剖分+线段树的点修改和查询问题

将打标记视为+1,那么如果一条链的sum不为0,节点祖先一点在这条链上,否则跳到链顶的父亲上

为了保证祖先最近,在链上二分,每次查询一下中点左边/右边的区间sum是否不为0,如果不为0,优先取右边

int n,q;
vector<int>e[maxn];
int dep[maxn];
int son[maxn];
int dfn[maxn];
int siz[maxn];
int top[maxn];
int rk[maxn];
int l[maxn];
int r[maxn];
int f[maxn];

struct node{
    int l,r;
    int sum;
}tr[4*maxn];
void pushup(int p){
    tr[p].sum=tr[ls].sum+tr[rs].sum;
}
void build(int p,int l,int r){
    tr[p].l=l;tr[p].r=r;
    if(l==r){
        tr[p].sum=0;return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);build(rs,mid+1,r);
}
void add(int p,int x,int k){
    if(tr[p].l==tr[p].r&&tr[p].l==x){
        tr[p].sum+=k;
        return;
    }
    int mid=tr[p].l+tr[p].r>>1;
    if(x<=mid)add(ls,x,k);
    else add(rs,x,k);
    pushup(p);
}
int query(int p,int l,int r){
    if(l<=tr[p].l&&tr[p].r<=r)return tr[p].sum;
    int mid=tr[p].l+tr[p].r>>1;
    int res=0;
    if(l<=mid)res+=query(ls,l,r);
    if(r>mid)res+=query(rs,l,r);
    return res;
}
int ef(int l,int r){
    if(l==r)return l;
    int mid=l+r>>1;
    int res=0;
    if(query(1,mid+1,r))res=ef(mid+1,r);
    else{
        res=ef(l,mid);
    }
    return res;
}
void query_fa(int u){
    int l=dfn[top[u]],r=dfn[u];
    if(!query(1,l,r))query_fa(f[top[u]]);
    else{
        cout<<rk[ef(l,r)]<<endl;
    }
}

void dfs1(int u,int fa){
    if(u!=1){
        dep[u]=dep[fa]+1;
    }
    f[u]=fa;
    son[u]=-1;
    siz[u]=1;
    for(int v:e[u]){
        if(v==fa)continue;

        dfs1(v,u);
        siz[u]+=siz[v];
        if(son[u]==-1||siz[v]>siz[son[u]])son[u]=v;
    }
}
int cnt;
void dfs2(int u,int t){
    dfn[u]=++cnt;
    rk[cnt]=u;
    top[u]=t;

    l[u]=cnt;
    if(son[u]==-1){
        r[u]=cnt;return ;
    }
    dfs2(son[u],t);


    for(int v:e[u]){
        if(v==f[u]||v==son[u])continue;
        dfs2(v,v);
    }

    r[u]=cnt;
}
void solve(){
    cin>>n>>q;
    rep(i,1,n-1){
        int u,v;cin>>u>>v;
        e[u].pb(v);e[v].pb(u);
    }
    dfs1(1,1);
    dfs2(1,1);
    build(1,1,n);
    add(1,1,1);
    
    while(q--){
        char ch;int x;cin>>ch>>x;
        if(ch=='C'){
            add(1,dfn[x],1);
        }else{
            query_fa(x);
        }
    }
}
posted @ 2025-05-24 14:58  Marinaco  阅读(11)  评论(0)    收藏  举报
//雪花飘落效果