学习笔记--点分树

感觉可以理解为带修点分治。

常用于解决与树原形态无关的带修改问题。 —— oi-wiki

点分树是通过更改原树形态使树的层数变为稳定 log⁡� 的一种重构树。就是通过点分治找重心的方式,将这一层重心为上一层重心的儿子。

所以对于很多暴力的复杂度是正确的。

一开始发现建树错了,然后发现是原先的点分治错了

子任务二可以直接拿点分树做,就是对于每个重心维护到这个点距离最近的点的距离。然后查询时就将重心看作 lca,直接暴跳就可以了。

void find(int x,int f){
    siz[x]=1;
    mx[x]=0;
    for(int i=head[x];i;i=nex[i]){
        int y=ver[i];
        if(y==f || vis[y]) continue; 
        find(y,x);
        siz[x]+=siz[y]; 
        mx[x]=max(mx[x],siz[y]);
    }
    mx[x]=max(mx[x],S-siz[x]);
    if(mx[root]>mx[x]) root=x;
}
void solve(int x){
    vis[x]=1;
    for(int i=head[x];i;i=nex[i]){
        int y=ver[i];
        if(vis[y]) continue;
        S=siz[y],root=0;
        find(y,x);
        fat[root]=x;
        solve(root);
    }
}
int mxxx[N];
void updata(int x){
    for(int i=x;i;i=fat[i]){
        int dis=ask_dist(i,x);
        mxxx[i]=min(mxxx[i],dis);
    }
}
int query(int x){
    int ans=inf;
    for(int i=x;i;i=fat[i]){
        int dis=ask_dist(x,i);
        if(mxxx[i]>(1ll<<50)) continue;
        ans=min(ans,dis+mxxx[i]);
    }
    return ans;
}

然后考虑两对点,做法就是点分治套点分树,对 x,a 进行点分治,然后将在这一层的操作处理掉,按顺序对 y,b 进行点分树上的修改和查询。具体就是先建一棵点分树,然后将每个操作压入所有涉及到的分治重心上,这里直接在点分树上跳就可以

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值