Qtree3

给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白
有两种操作:
0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑)
1 v : 询问1到v的路径上的第一个黑点,若无,输出-1

方法1:树剖线段树上维护深度最小的黑点。
方法2:统计点到根的路径有几个黑点,倍增向上跳。

#include<bits/stdc++.h>
using namespace std;

const int MAXN=1e5+5;
const int INF=1e9+7;

typedef pair<int,int>par;
#define mp make_pair

struct edge{
    int to,next;
}e[MAXN<<1];

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

int n,m;
int fa[MAXN],hson[MAXN],size[MAXN],dep[MAXN];
void dfs1(int u,int father){
    size[u]=1;
    dep[u]=dep[father]+1;
    fa[u]=father;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==father)continue;
        dfs1(v,u);
        size[u]+=size[v];
        if(!hson[u]||size[hson[u]]<size[v])hson[u]=v;       
    }
}

int id[MAXN],rl[MAXN],top[MAXN],num=0;
void dfs2(int u,int tp){
    top[u]=tp;
    id[u]=++num;
    rl[num]=u;
    if(hson[u])dfs2(hson[u],tp);
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u]||v==hson[u])continue;
        dfs2(v,v);
    }
}

int deeeeep[MAXN<<2],blk[MAXN<<2];
struct xds{
    #define lson (o<<1)
    #define rson (o<<1|1)
    inline void pushup(int o){
        if(deeeeep[lson]<deeeeep[rson]) deeeeep[o]=deeeeep[lson],blk[o]=blk[lson];
        else deeeeep[o]=deeeeep[rson],blk[o]=blk[rson];
    }
    void build(int o,int l,int r){
        if(l==r){deeeeep[o]=INF;blk[o]=-1;return;}
        int mid=l+r>>1;
        build(lson,l,mid);build(rson,mid+1,r);
        pushup(o);
    }
    par query(int o,int l,int r,int ql,int qr){
        if(ql<=l&&qr>=r){return mp(deeeeep[o],blk[o]);}
        int mid=l+r>>1;
        par t1=mp(INF,-1),t2=mp(INF,-1);
        if(ql<=mid){
            t1=query(lson,l,mid,ql,qr); 
        }
        if(qr>mid){
            t2=query(rson,mid+1,r,ql,qr);   
            if(t2.first<t1.first)t1.first=t2.first,t1.second=t2.second;
        }
        return mp(t1.first,t1.second);
    }
    void change(int o,int l,int r,int pos){
        if(l==r){
            if(deeeeep[o]!=INF)deeeeep[o]=INF,blk[o]=-1;
            else deeeeep[o]=dep[rl[l]],blk[o]=rl[l];
            return;
        }   
        int mid=l+r>>1;
        if(pos<=mid)change(lson,l,mid,pos);
        else change(rson,mid+1,r,pos);
        pushup(o);
    }
}T;

int chain_query(int x,int y){
    int tx=top[x],ty=top[y];
    par t1=mp(INF,-1),t2=mp(INF,-1);
    while(tx!=ty){
        if(dep[tx]<dep[ty]){
            t2=T.query(1,1,n,id[ty],id[y]); 
            if(t2.first<t1.first)t1.first=t2.first,t1.second=t2.second;
            y=fa[ty];
        }
        else{
            t2=T.query(1,1,n,id[tx],id[x]); 
            if(t2.first<t1.first)t1.first=t2.first,t1.second=t2.second;
            x=fa[tx];
        }
        tx=top[x],ty=top[y];
    }
    if(dep[x]<dep[y])swap(x,y);
    t2=T.query(1,1,n,id[y],id[x]);
    if(t2.first<t1.first)t1.first=t2.first,t1.second=t2.second;
    return t1.second;
}

int main(){
    int u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dfs1(1,1);
    dfs2(1,1);
    T.build(1,1,n);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        if(u)printf("%d\n",chain_query(u,v));
        else T.change(1,1,n,id[v]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值