链接
题解
动态树分治
这个名字虽然看上去貌似挺吓人的,其实原理很简单
就是你点分治的时候不是先找到一个重心 G G G吗,然后你利用这个重心 G G G把树分成了好几块,接下来在每个子树里面再去找重心 g 1 , g 2 , g 3 , … g_1,g_2,g_3,\dots g1,g2,g3,…,那么我令 g 1 , g 2 , g 3 , … g_1,g_2,g_3,\dots g1,g2,g3,…成为 G G G的孩子,这样递归建立一棵树,这个树就被称为点分树
点分树的树高是 O ( l o g n ) O(logn) O(logn)的
点分树用来干啥呢?
可以想一想,我们在做点分治的时候,是不是通过枚举重心就能够遍历到所有的路径?这里我们依然利用重心的这个特性
以某个点 u u u为端点的所有路径怎么遍历呢?很简单,如果一条路径以 u u u为端点,那么这个路径肯定经过点分树中从 u u u到根节点这条链上的某个点。这一点从点分治的过程就可以看出来。
那么这个题怎么做呢?很简单,在点分树的每个点 u u u建立一个以苹果成熟度为下标的线段树,维护从 u u u到其子树(点分树的子树)中每个节点的真实距离的最小值(真实距离=在原来的树上的距离)。
修改的时候沿着点分树往上跳,一边跳一边修改,查询的时候同理。
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define eps 1e-8
#define maxn 100010
#define maxe 200010
#define maxk 17
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
int read(int x=0)
{
int c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
struct Graph
{
int etot, head[maxn], to[maxe], next[maxe], w[maxe];
void clear(int N)
{
for(int i=1;i<=N;i++)head[i]=0;
etot=0;
}
void adde(int a, int b, int c=0){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
#define forp(_,__) for(auto p=__.head[_];p;p=__.next[p])
}G;
struct Centroid_Decomposition
{
int grey[maxn], depth[maxn], size[maxn], dist[maxn], lis[maxn], fa[maxn];
void dfs(int pos, int pre, Graph& G) //这个用来处理出每个点的深度
{
lis[++*lis]=pos;
size[pos]=1;
forp(pos,G)if(G.to[p]!=pre and !grey[G.to[p]])
{
depth[G.to[p]]=depth[pos]+1;
dist[G.to[p]]=dist[pos]+G.w[p];
dfs(G.to[p],pos,G);
size[pos]+=size[G.to[p]];
}
}
void findG(int pos, int pre, Graph& G, int& g, int& gsum, int nowsum, int node_tot)//找重心
{
if(nowsum<gsum)g=pos, gsum=nowsum;
forp(pos,G)if(G.to[p]!=pre and !grey[G.to[p]])
findG( G.to[p], pos, G, g, gsum, nowsum+(node_tot-2*size[G.to[p]]), node_tot );
}
void solve(int pos, Graph& G, int Fa)
{
*lis=0; depth[pos]=0; dfs(pos,0,G);
int g=pos, gsum=0, i;
rep(i,1,*lis)gsum+=depth[lis[i]];
findG(pos,0,G,g,gsum,gsum,*lis);
grey[g]=1;
fa[g]=Fa;
forp(g,G)if(!grey[G.to[p]])solve(G.to[p],G,g);
}
void run(Graph& G)
{
cl(grey);
solve(1,G,0);
}
}CD;
struct DynamicSegmentTree
{
int pool[20000000], tot, Min[20000000], ch[20000000][2];
int New(int v)
{
Min[++tot]=v;
return tot;
}
int getmin(int o){return o?Min[o]:iinf;}
void upd(int o)
{
Min[o] = min(getmin(ch[o][0]),getmin(ch[o][1]));
}
void init()
{
int i;rep(i,1,tot)ch[i][0]=ch[i][1]=0;
tot=0;
}
int insert(int o, int pos, int v, int l, int r)
{
int mid(l+r>>1);
if(!o)o=New(v);
else Min[o]=min(Min[o],v);
if(l==r)return o;
if(pos<=mid)ch[o][0]=insert(ch[o][0],pos,v,l,mid);
else ch[o][1]=insert(ch[o][1],pos,v,mid+1,r);
return o;
}
int qmin(int o, int wantl, int wantr, int l, int r)
{
int mid(l+r>>1), ret=iinf;
if(wantl<=l and r<=wantr)return getmin(o);
if(wantl<=mid)ret=min(ret,qmin(ch[o][0],wantl,wantr,l,mid));
if(wantr>mid)ret=min(ret,qmin(ch[o][1],wantl,wantr,mid+1,r));
return ret;
}
}segtree;
struct Doubling_LCA
{
int f[maxn][maxk+1], depth[maxn];
void clear(int n){for(int i=1;i<=n;i++)depth[i]=0, cl(f[i]);}
void dfs(Graph &G, int pos, int pre)
{
for(auto k=1;(1<<k)<=depth[pos];k++)f[pos][k]=f[f[pos][k-1]][k-1];
for(auto p(G.head[pos]);p;p=G.next[p])
if(G.to[p]!=pre)
{
f[G.to[p]][0]=pos;
depth[G.to[p]]=depth[pos]+1;
dfs(G,G.to[p],pos);
}
}
void run(Graph &G, int root)
{
depth[root]=1;
dfs(G,root,0);
}
int q(int x, int y)
{
if(depth[x]<depth[y])swap(x,y);
for(auto k(maxk);~k;k--)
if(depth[f[x][k]]>=depth[y])
x=f[x][k];
if(x==y)return x;
for(auto k(maxk);~k;k--)
if(f[x][k]!=f[y][k])
x=f[x][k], y=f[y][k];
return f[x][0];
}
int jp(int x, int b)
{
for(auto k=0;k<=maxk;k++)
if(b&(1<<k))x=f[x][k];
return x;
}
}db;
struct Easy_Tree
{
int depth[maxn], dist[maxn], tid[maxn], rtid[maxn], tim, size[maxn], rev[maxn];
void dfs(int pos, int pre, Graph& G)
{
tid[pos]=++tim;
rev[tid[pos]]=pos;
size[pos]=1;
forp(pos,G)if(G.to[p]!=pre)
{
depth[G.to[p]]=depth[pos]+1;
dist[G.to[p]]=dist[pos]+G.w[p];
dfs(G.to[p],pos,G);
size[pos]+=size[G.to[p]];
}
rtid[pos]=tim;
}
void run(Graph& G, int root)
{
tim=0;
depth[root]=1;
dfs(1,0,G);
}
}et;
int root[maxn], a[maxn];
void NewApple(int u, int x)
{
int t=u;
while(t)
{
int lca = db.q(u,t), L = et.dist[u] + et.dist[t] - 2*et.dist[lca];
root[t]=segtree.insert(root[t],x,L,1,10000);
t = CD.fa[t];
}
}
int main()
{
int n=read(), m=read(), u, v, w, x, y, i;
rep(i,1,n)a[i]=read();
rep(i,1,n-1)
{
u=read(), v=read(), w=read();
G.adde(u,v,w), G.adde(v,u,w);
}
et.run(G,1);
db.run(G,1);
CD.run(G);
rep(i,1,n)NewApple(i,a[i]);
while(m--)
{
int type=read();
if(type==1)
{
u=read();
x=read();
NewApple(u,x);
}
else
{
u=read();
x=read();
y=read();
int t=u, ans=iinf;
while(t)
{
int lca = db.q(u,t), L = et.dist[u] + et.dist[t] - 2*et.dist[lca];
ans = min( ans, L + segtree.qmin(root[t],x,y,1,10000) );
t = CD.fa[t];
}
printf("%d\n",ans==iinf?-1:ans*2);
}
}
return 0;
}