点分树就是按照点分治的顺序建树,他是可修改的,注意这个树维护不是原来的父子关系,有可能会跨层,所以我们千万不要去想他的父子关系,因为你会发现并不对应。。 这个树会特别胖,也就是层数特别低,并且它的好处是能不重不漏地刚好维护任意两点之间的距离关系,我们可以使用划分的思想,任意两点的距离刚好对于他们的祖先,而他们祖先并不多,最多只有log(n)个,然后再套个数据结构例如权值线段树,可以干很多事情,建树过程的话就是每次找子树的重心当根,然后不断迭代。。。写这种算法唯一需要注意的就是代码别抄错,然后暴力所有点当根的贡献,虽然看起来可能n^2,但如果用分治的眼光去看的话,总共log层,每一层操作的节点数最多为n,所以并不多。
例题
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
struct node {
int l;
int r;
int minv;
void node_init()
{
minv=2e9;
}
} tr[N*200];
bool st[N];
int idx;
int a[N];
int root[N];
vector<pair<int,int>>v[N];
vector<pair<int,int>>father[N];
void insert(int &u,int l,int r,int k,int dist) {
if(!u) {
u=++idx;
tr[u].minv=2e9;
}
tr[u].minv=min(tr[u].minv,dist);
if(l==r){
return ;
}
int mid=l+r>>1;
if(k<=mid)
insert(tr[u].l,l,mid,k,dist);
else
insert(tr[u].r,mid+1,r,k,dist);
}
int query(int u,int l,int r,int ql,int qr)
{
if(!u) return 2e9;
if(l>=ql && r<=qr) return tr[u].minv;
int mid=l+r>>1;
int res=2e9;
if(ql<=mid) res=min(res,query(tr[u].l,l,mid,ql,qr));
if(mid<qr) res=min(res,query(tr[u].r,mid+1,r,ql,qr));
return res;
}
int get_size(int u,int fa) {
if(st[u]) return 0;
int sum=1;
for(auto jj:v[u]) {
int j=jj.first;
int w=jj.second;
if(j==fa) continue;
sum+=get_size(j,u);
}
return sum;
}
int get_wc(int u,int fa,int tot,int &wc) {
if(st[u]) return 0;
int sum=1;
int maxv=0;
for(auto jj:v[u]) {
int j=jj.first;
int w=jj.second;
if(j==fa) continue;
int sz=get_wc(j,u,tot,wc);
maxv=max(maxv,sz);
sum+=sz;
}
if(max(tot-sum,maxv)<=tot/2) {
wc=u;
}
return sum;
}
void build_apple_tree(int u,int fa,int rt,int dist) {
if(st[u]) return;
insert(root[rt],1,10000,a[u],dist);
father[u].push_back({rt,dist});
for(auto jj:v[u]) {
int j=jj.first;
int w=jj.second;
if(j==fa) continue;
build_apple_tree(j,u,rt,dist+w);
}
}
void dfs(int u,int fa) {
if(st[u]) return ;
int sz=get_size(u,fa);
get_wc(u,fa,sz,u);
build_apple_tree(u,fa,u,0);
st[u]=true;
for(auto jj:v[u]) {
int j=jj.first;
int w=jj.second;
if(j==fa) continue;
dfs(j,u);
}
}
void solve() {
tr[0].minv=2e9;
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
}
for(int i=0;i<n-1;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
v[a].push_back({b,c});
v[b].push_back({a,c});
}
dfs(1,-1);
while(m--){
int op;
scanf("%d",&op);
if(op==1){
int u,x;
scanf("%d%d",&u,&x);
for(auto jj:father[u]){
int j=jj.first;
int w=jj.second;
insert(root[j],1,10000,x,w);
}
}
else{
int u,x,y;
scanf("%d%d%d",&u,&x,&y);
int res=2e9;
for(auto jj:father[u]){
int j=jj.first;
int w=jj.second;
res=min(res,w+query(root[j],1,10000,x,y));
}
if(res==2e9) {
printf("-1\n");
continue;
}
res*=2;
printf("%d\n",res);
}
}
}
signed main() {
solve();
}