ybtAu「树上问题」第1章 树链剖分
A. 【例题1】树的统计
板子。树链剖分 + 线段树。
#include <iostream>
#define N 100005
int n,m,hed[N],tal[N],nxt[N],cnte,rt;
void de(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
namespace SGT
{
int mx[N<<1],sum[N<<1],ls[N<<1],rs[N<<1],idx;
#define mid (lb+rb>>1)
void pu(int x) {mx[x]=std::max(mx[ls[x]],mx[rs[x]]),sum[x]=sum[ls[x]]+sum[rs[x]];}
void md(int &x,int t,int k,int lb,int rb)
{
if(!x) x=++idx;
if(lb==rb) return mx[x]=sum[x]=k,void();
(t<=mid)?md(ls[x],t,k,lb,mid):md(rs[x],t,k,mid+1,rb);
pu(x);
}
int qmx(int x,int l,int r,int lb,int rb)
{
if(!x) return -1e9;
if(l<=lb&&rb<=r) return mx[x];
int ret=-1e9;
if(l<=mid) ret=qmx(ls[x],l,r,lb,mid);
if(r>mid) ret=std::max(ret,qmx(rs[x],l,r,mid+1,rb));
return ret;
}
int qsum(int x,int l,int r,int lb,int rb)
{
if(!x) return 0;
if(l<=lb&&rb<=r) return sum[x];
int ret=0;
if(l<=mid) ret=qsum(ls[x],l,r,lb,mid);
if(r>mid) ret+=qsum(rs[x],l,r,mid+1,rb);
return ret;
}
#undef mid
};
namespace HLD
{
int dfn[N],li[N],dep[N],fa[N],son[N],siz[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dep[tal[i]]=dep[x]+1,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void dfs2(int x,int tp)
{
if(!x) return;
dfn[x]=++idx,dfs2(son[x],top[x]=tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) dfs2(tal[i],tal[i]);
}
void md(int x,int t) {SGT::md(rt,dfn[x],t,1,n);}
int qmx(int x,int y)
{
int ret=-1e9;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
ret=std::max(ret,SGT::qmx(rt,dfn[top[x]],dfn[x],1,n));
x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
ret=std::max(ret,SGT::qmx(rt,dfn[x],dfn[y],1,n));
return ret;
}
int qsum(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
ret+=SGT::qsum(rt,dfn[top[x]],dfn[x],1,n);
x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
ret+=SGT::qsum(rt,dfn[x],dfn[y],1,n);
return ret;
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n;
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,de(u,v),de(v,u);
HLD::dfs1(1),HLD::dfs2(1,1);
for(int i=1,x;i<=n;i++) std::cin>>x,HLD::md(i,x);
std::cin>>m;
for(int i=1,x,y;i<=m;i++)
{
std::string op;
std::cin>>op>>x>>y;
if(op[1]=='H') HLD::md(x,y);
if(op[1]=='M') std::cout<<HLD::qmx(x,y)<<'\n';
if(op[1]=='S') std::cout<<HLD::qsum(x,y)<<'\n';
}
}
B. 树上染色
结构体存每段颜色数量、段首段尾颜色,线段树维护,查询时存储左链和右链,最后合并。
#include <iostream>
#define N 200005
#define piii std::pair<int,std::pair<int,int> >
int n,m,a[N],hed[N],tal[N],nxt[N],cnte,rt,col[N];
void de(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
piii mg(piii x,piii y)
{
piii ret;
ret.first=x.first+y.first;
if(x.second.second==y.second.first) ret.first--;
ret.second.first=x.second.first,ret.second.second=y.second.second;
return ret;
}
namespace SGT
{
piii d[N<<2];
int tg[N<<2],ls[N<<2],rs[N<<2],idx;
#define mid (lb+rb>>1)
void pu(int x) {d[x]=mg(d[ls[x]],d[rs[x]]);}
void mt(int x,int t) {d[x]={1,{t,t}},tg[x]=t;}
void pd(int x)
{
if(tg[x]==-1) return;
if(!ls[x]) ls[x]=++idx;
if(!rs[x]) rs[x]=++idx;
mt(ls[x],tg[x]),mt(rs[x],tg[x]),tg[x]=-1;
}
void md(int &x,int l,int r,int t,int lb,int rb)
{
if(!x) tg[x=++idx]=-1;
if(l<=lb&&rb<=r) return mt(x,t),void();
pd(x);
if(l<=mid) md(ls[x],l,r,t,lb,mid);
if(r>mid) md(rs[x],l,r,t,mid+1,rb);
pu(x);
}
piii qr(int x,int l,int r,int lb,int rb)
{
if(!x) return {0,{0,0}};
if(l<=lb&&rb<=r) return d[x];
pd(x);
if(r<=mid) return qr(ls[x],l,r,lb,mid);
if(l>mid) return qr(rs[x],l,r,mid+1,rb);
return mg(qr(ls[x],l,r,lb,mid),qr(rs[x],l,r,mid+1,rb));
}
#undef mid
};
namespace HLD
{
int dfn[N],dep[N],fa[N],son[N],siz[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dep[tal[i]]=dep[x]+1,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void dfs2(int x,int tp)
{
if(!x) return;
dfn[x]=++idx,dfs2(son[x],top[x]=tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) dfs2(tal[i],tal[i]);
}
void md(int x,int y,int t)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
SGT::md(rt,dfn[top[x]],dfn[x],t,1,n),x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
SGT::md(rt,dfn[x],dfn[y],t,1,n);
}
int qr(int x,int y)
{
piii lc={0,{0,0}},rc={0,{0,0}};
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
if(!lc.first) lc=SGT::qr(rt,dfn[top[x]],dfn[x],1,n);
else lc=mg(SGT::qr(rt,dfn[top[x]],dfn[x],1,n),lc);
x=fa[top[x]];
}
else
{
if(!rc.first) rc=SGT::qr(rt,dfn[top[y]],dfn[y],1,n);
else rc=mg(SGT::qr(rt,dfn[top[y]],dfn[y],1,n),rc);
y=fa[top[y]];
}
}
if(dep[x]>dep[y])
{
if(!lc.first) lc=SGT::qr(rt,dfn[y],dfn[x],1,n);
else lc=mg(SGT::qr(rt,dfn[y],dfn[x],1,n),lc);
}
else
{
if(!rc.first) rc=SGT::qr(rt,dfn[x],dfn[y],1,n);
else rc=mg(SGT::qr(rt,dfn[x],dfn[y],1,n),rc);
}
return lc.first+rc.first-(lc.second.first==rc.second.first);
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
for(int i=1;i<=n;i++) std::cin>>col[i];
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,de(u,v),de(v,u);
HLD::dfs1(1),HLD::dfs2(1,1);
for(int i=1;i<=n;i++) SGT::md(rt,HLD::dfn[i],HLD::dfn[i],col[i],1,n);
for(int i=1,x,y,z;i<=m;i++)
{
char op;
std::cin>>op>>x>>y;
if(op=='C') std::cin>>z,HLD::md(x,y,z);
if(op=='Q') std::cout<<HLD::qr(x,y)<<'\n';
}
}
C. 旅行留宿
对每种颜色开一棵动态开点线段树。
#include <iostream>
#define N 200005
int n,m,wt[N],col[N],hed[N],tal[N],nxt[N],cnte;
void de(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
struct Node
{
Node *ls,*rs;
int mx,sum;
Node():ls(nullptr),rs(nullptr),mx(0),sum(0) {}
void pu()
{
mx=sum=0;
if(ls) mx=std::max(mx,ls->mx),sum+=ls->sum;
if(rs) mx=std::max(mx,rs->mx),sum+=rs->sum;
}
} *rt[N];
namespace SGT
{
#define mid (lb+rb>>1)
void md(Node *&x,int t,int k,int lb,int rb)
{
if(!x) x=new Node();
if(lb==rb) return x->sum=x->mx=k,void();
(t<=mid)?md(x->ls,t,k,lb,mid):md(x->rs,t,k,mid+1,rb);
x->pu();
}
int qsum(Node *x,int l,int r,int lb,int rb)
{
if(!x) return 0;
if(l<=lb&&rb<=r) return x->sum;
int ret=0;
if(l<=mid) ret=qsum(x->ls,l,r,lb,mid);
if(r>mid) ret+=qsum(x->rs,l,r,mid+1,rb);
return ret;
}
int qmx(Node *x,int l,int r,int lb,int rb)
{
if(!x) return 0;
if(l<=lb&&rb<=r) return x->mx;
int ret=0;
if(l<=mid) ret=qmx(x->ls,l,r,lb,mid);
if(r>mid) ret=std::max(ret,qmx(x->rs,l,r,mid+1,rb));
return ret;
}
#undef mid
};
namespace HLD
{
int dfn[N],dep[N],fa[N],son[N],siz[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dep[tal[i]]=dep[x]+1,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void dfs2(int x,int tp)
{
if(!x) return;
dfn[x]=++idx,SGT::md(rt[col[x]],dfn[x],wt[x],1,n),dfs2(son[x],top[x]=tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) dfs2(tal[i],tal[i]);
}
void mc(int x,int t) {SGT::md(rt[col[x]],dfn[x],0,1,n),SGT::md(rt[col[x]=t],dfn[x],wt[x],1,n);}
void md(int x,int t) {SGT::md(rt[col[x]],dfn[x],wt[x]=t,1,n);}
int qsum(int x,int y)
{
int ret=0,C=col[x];
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
ret+=SGT::qsum(rt[C],dfn[top[x]],dfn[x],1,n),x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
return ret+SGT::qsum(rt[C],dfn[x],dfn[y],1,n);
}
int qmx(int x,int y)
{
int ret=0,C=col[x];
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
ret=std::max(ret,SGT::qmx(rt[C],dfn[top[x]],dfn[x],1,n)),x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
return std::max(ret,SGT::qmx(rt[C],dfn[x],dfn[y],1,n));
}
}
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
for(int i=1;i<=n;i++) std::cin>>wt[i]>>col[i];
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,de(u,v),de(v,u);
HLD::dfs1(1),HLD::dfs2(1,1);
for(int i=1,x,y;i<=m;i++)
{
std::string op;
std::cin>>op>>x>>y;
if(op[1]=='C') HLD::mc(x,y);
if(op[1]=='W') HLD::md(x,y);
if(op[1]=='S') std::cout<<HLD::qsum(x,y)<<'\n';
if(op[1]=='M') std::cout<<HLD::qmx(x,y)<<'\n';
}
}
D. 深度求和
令 \(anc(x)\) 表示节点 \(x\) 的祖先集合,有:
\[\large\begin{align}
ans&=\sum_{i=l}^r dep[LCA(i,z)] \nonumber\\
&=\sum_{i=l}^r \sum_{j\in anc(LCA(i,z))}1 \nonumber\\
&=\sum_{i=l}^r \sum_{j\in anc(i),j\in anc(z)}1 \nonumber\\
&=\sum_{j\in anc(z)}\sum_{i=l}^r[j\in anc(i)]\nonumber
\end{align}
\]
考虑每个点对答案的贡献,发现它对从它到根的链上每个点都有 \(1\) 的贡献。使用树链剖分进行链加,查询即求树链和。
由于查询的是区间,把询问离线下来扫描线,进行差分即可。
区间加可以树状数组维护。
记得要取模
#include <iostream>
#include <vector>
#define N 100005
#define mod 201314
int n,m,hed[N],tal[N],nxt[N],cnte,ans[N];
std::vector<std::pair<int,std::pair<int,int> > > buc[N];
void de(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
namespace BIT2
{
struct BIT
{
int f[N],r;
void c(int x,int t) {for(;x<=n;x+=x&-x) f[x]+=t;}
int q(int x) {for(r=0;x;x-=x&-x) r+=f[x];return r;}
} tr1,tr2;
void c(int x,int t) {tr1.c(x,t),tr2.c(x,t*x);}
int q(int x) {return (x+1)*tr1.q(x)-tr2.q(x);}
void md(int l,int r,int t) {c(l,t),c(r+1,-t);}
int qr(int l,int r) {return q(r)-q(l-1);}
};
namespace HLD
{
int dfn[N],dep[N],fa[N],son[N],siz[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dep[tal[i]]=dep[x]+1,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void dfs2(int x,int tp)
{
if(!x) return;
dfn[x]=++idx,dfs2(son[x],top[x]=tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) dfs2(tal[i],tal[i]);
}
void md(int x) {while(x) BIT2::md(dfn[top[x]],dfn[x],1),x=fa[top[x]];}
int qr(int x) {int ret=0;while(x) ret+=BIT2::qr(dfn[top[x]],dfn[x]),x=fa[top[x]];return ret;}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m;
for(int i=2,x;i<=n;i++) std::cin>>x,de(x+1,i),de(i,x+1);
HLD::dfs1(1),HLD::dfs2(1,1);
for(int i=1,l,r,x;i<=m;i++)
{
std::cin>>l>>r>>x,x++;
buc[l].push_back({i,{x,-1}}),buc[r+1].push_back({i,{x,1}});
}
for(int i=1;i<=n;i++)
{
HLD::md(i);
for(auto j:buc[i])
{
int id=j.first,x=j.second.first,p=j.second.second;
ans[id]+=HLD::qr(x)*p;
}
}
for(int i=1;i<=m;i++) std::cout<<ans[i]%mod<<'\n';
}
E. 动态树
为防止算重,对每条链,直接使用树链剖分找到所求区间,最后把 \(K\) 个询问的 \(O(K\log n)\) 个区间取并集,再区间求和即可。
#include <iostream>
#include <algorithm>
#include <vector>
#define N 400005
#define int long long
const int mod=1ll<<31;
int n,m,hed[N],tal[N],nxt[N],cnte;
void de(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
std::vector<std::pair<int,int> > g;
namespace BIT2
{
struct BIT
{
int f[N],r;
void c(int x,int t) {for(;x<=n;x+=x&-x) (f[x]+=t)%=mod;}
int q(int x) {r=0;for(;x;x-=x&-x) (r+=f[x])%=mod;return r;}
} tr1,tr2;
void c(int x,int t) {tr1.c(x,t),tr2.c(x,t*x%mod);}
int q(int x) {return ((x+1)*tr1.q(x)%mod-tr2.q(x)+mod)%mod;}
void md(int l,int r,int t) {c(l,t),c(r+1,mod-t);}
int qr(int l,int r) {return (q(r)-q(l-1)+mod)%mod;}
};
namespace HLD
{
int dfn[N],dep[N],fa[N],son[N],siz[N],top[N],idx;
void dfs1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dep[tal[i]]=dep[x]+1,dfs1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void dfs2(int x,int tp)
{
if(!x) return;
dfn[x]=++idx,dfs2(son[x],top[x]=tp);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) dfs2(tal[i],tal[i]);
}
void md(int x,int t) {BIT2::md(dfn[x],dfn[x]+siz[x]-1,t);}
void addseq(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
g.push_back({dfn[top[x]],dfn[x]});
x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
g.push_back({dfn[x],dfn[y]});
}
int qr()
{
std::sort(g.begin(),g.end());
for(int i=1;i<g.size();i++) if(g[i].first<=g[i-1].second)
{
g[i-1].second=std::max(g[i-1].second,g[i].second);
g.erase(g.begin()+i);
i--;
}
int ret=0;
for(int i=0;i<g.size();i++) (ret+=BIT2::qr(g[i].first,g[i].second))%=mod;
return ret;
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n;
for(int i=1,u,v;i<n;i++) std::cin>>u>>v,de(u,v),de(v,u);
HLD::dfs1(1),HLD::dfs2(1,1);
std::cin>>m;
for(int i=1,op;i<=m;i++)
{
std::cin>>op;
if(op==0)
{
int u,dt;
std::cin>>u>>dt;
HLD::md(u,dt);
}
if(op==1)
{
g.clear();
int l;
std::cin>>l;
for(int j=1,u,v;j<=l;j++) std::cin>>u>>v,HLD::addseq(u,v);
std::cout<<HLD::qr()<<'\n';
}
}
}
F. 采矿战略
DDP 还在追我。
令 \(f_{u,i}\) 表示 \(u\) 节点安排 \(i\) 个人的的答案,从 \(v\) 转移到 \(u\) 即为:
\[\large f'_{u,i}=\max_{j\le i} f_{u,j}+f_{v,i-j}
\]
子树内部分可以用线段树求解,链部分用线段树维护每个 \(i\) 的 \(f_{u,i}\) 最大值,最后将两部分合并即可。
#include <iostream>
#include <algorithm>
#include <vector>
#define int long long
#define N 40005
const int X=1<<16,Y=(1ll<<31)-1;
int n,m,q,hed[N],tal[N],nxt[N],cnte,rt,A,B,Q;
void de(int u,int v) {tal[++cnte]=v,nxt[cnte]=hed[u],hed[u]=cnte;}
inline int Getint()
{
A=((A^B)+B/X+B*X)&Y;
B=((A^B)+A/X+A*X)&Y;
return (A^B)%Q;
}
std::vector<int> gen()
{
std::vector<int> ret(m+1);
for(int i=1;i<=m;i++) ret[i]=Getint();
std::sort(ret.begin(),ret.end());
return ret;
}
std::vector<int> mg(std::vector<int> x,std::vector<int> y)
{
if(!x.size()) return y;
if(!y.size()) return x;
std::vector<int> ret(m+1);
for(int i=0;i<=m;i++) for(int j=0;j+i<=m;j++) ret[i+j]=std::max(ret[i+j],x[i]+y[j]);
return ret;
}
std::vector<int> gmx(std::vector<int> x,std::vector<int> y)
{
if(!x.size()) return y;
if(!y.size()) return x;
for(int i=0;i<=m;i++) x[i]=std::max(x[i],y[i]);
return x;
}
namespace SGT
{
std::vector<int> d[N<<2],mx[N<<2];
int ls[N<<2],rs[N<<2],idx;
#define mid (lb+rb>>1)
void md(int &x,int t,std::vector<int> k,int lb,int rb)
{
if(!x) x=++idx;
if(lb==rb) return d[x]=mx[x]=k,void();
(t<=mid)?md(ls[x],t,k,lb,mid):md(rs[x],t,k,mid+1,rb);
d[x]=mg(d[ls[x]],d[rs[x]]),mx[x]=gmx(mx[ls[x]],mx[rs[x]]);
}
std::vector<int> qr(int x,int l,int r,int lb,int rb)
{
if(!x) return std::vector<int>();
if(l<=lb&&rb<=r) return d[x];
if(r<=mid) return qr(ls[x],l,r,lb,mid);
if(l>mid) return qr(rs[x],l,r,mid+1,rb);
return mg(qr(ls[x],l,r,lb,mid),qr(rs[x],l,r,mid+1,rb));
}
std::vector<int> qmx(int x,int l,int r,int lb,int rb)
{
if(!x) return std::vector<int>();
if(l<=lb&&rb<=r) return mx[x];
if(r<=mid) return qmx(ls[x],l,r,lb,mid);
if(l>mid) return qmx(rs[x],l,r,mid+1,rb);
return gmx(qmx(ls[x],l,r,lb,mid),qmx(rs[x],l,r,mid+1,rb));
}
#undef mid
};
namespace HLD
{
int dfn[N],dep[N],fa[N],son[N],siz[N],top[N],idx;
void d1(int x)
{
siz[x]=1;
for(int i=hed[x];i;i=nxt[i]) if(!siz[tal[i]])
{
fa[tal[i]]=x,dep[tal[i]]=dep[x]+1,d1(tal[i]),siz[x]+=siz[tal[i]];
if(siz[tal[i]]>siz[son[x]]) son[x]=tal[i];
}
}
void d2(int x,int t)
{
if(!x) return;
dfn[x]=++idx,d2(son[x],top[x]=t);
for(int i=hed[x];i;i=nxt[i]) if(!top[tal[i]]) d2(tal[i],tal[i]);
}
std::vector<int> qsub(int x) {return SGT::qr(rt,dfn[x],dfn[x]+siz[x]-1,1,n);}
std::vector<int> qr(int x,int y)
{
if(x==y) return std::vector<int>();
std::vector<int> ans(m+1);
x=fa[x];
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
ans=gmx(ans,SGT::qmx(rt,dfn[top[x]],dfn[x],1,n)),x=fa[top[x]];
}
if(dep[x]>dep[y]) std::swap(x,y);
return gmx(ans,SGT::qmx(rt,dfn[x],dfn[y],1,n));
}
};
signed main()
{
std::ios::sync_with_stdio(0);
std::cin.tie(0),std::cout.tie(0);
std::cin>>n>>m>>A>>B>>Q;
for(int i=2,x;i<=n;i++) std::cin>>x,de(x,i);
HLD::d1(1),HLD::d2(1,1);
for(int i=1;i<=n;i++) SGT::md(rt,HLD::dfn[i],gen(),1,n);
std::cin>>q;
for(int i=1,op,x,y;i<=q;i++)
{
std::cin>>op>>x;
if(op==0) SGT::md(rt,HLD::dfn[x],gen(),1,n);
if(op==1)
{
std::cin>>y;
std::vector<int> ans=mg(HLD::qsub(x),HLD::qr(x,y));
std::cout<<ans[m]<<'\n';
}
}
}

浙公网安备 33010602011771号