树链剖分题解
P3379 LCA模板
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+10;
int n,m,root,mod;
int h[N],e[N<<1],ne[N<<1],idx;
int dep[N],top[N],id[N],cnt,fa[N],son[N],sz[N];
struct node
{
int add,sum;
int l,r;
}tr[N<<4];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int depth)
{
dep[u]=depth,fa[u]=f;
sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
if(!son[u]) return ;
dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>m>>root;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs1(root,-1,1);
dfs2(root,root);
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) v=fa[top[v]];
else u=fa[top[u]];
}
if(dep[u]<dep[v]) cout<<u<<'\n';
else cout<<v<<'\n';
}
}
P3384 树链剖分模板
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,m,root,mod;
int h[N],e[N<<1],ne[N<<1],idx;
int dep[N],top[N],id[N],cnt,fa[N],son[N],sz[N],w[N],nw[N];
struct node
{
int add,sum;
int l,r;
}tr[N<<4];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int depth)
{
dep[u]=depth,fa[u]=f;
sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++cnt,nw[cnt]=w[u];
if(!son[u]) return ;
dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void pushup(int u)
{
tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum)%mod;
}
void pushdown(int u)
{
if(tr[u].add)
{
tr[u<<1].add+=tr[u].add,tr[u<<1|1].add+=tr[u].add;
(tr[u<<1].sum+=tr[u].add*(tr[u<<1].r-tr[u<<1].l+1))%=mod;
(tr[u<<1|1].sum+=tr[u].add*(tr[u<<1|1].r-tr[u<<1|1].l+1))%=mod;
tr[u].add=0;
}
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
if(l==r)
{
tr[u].add=0,tr[u].sum=nw[l]%mod;
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int k)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].add+=k,tr[u].sum=(tr[u].sum+k*(tr[u].r-tr[u].l+1))%mod;
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,k);
if(r>mid) modify(u<<1|1,l,r,k);
pushup(u);
}
void modify_path(int u,int v,int k)//修改u->v路径上的点
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify(1,id[top[u]],id[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
modify(1,id[v],id[u],k);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
return tr[u].sum%mod;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
int res=0;
if(l<=mid) res=(res+query(u<<1,l,r))%mod;
if(r>mid) res=(res+query(u<<1|1,l,r))%mod;
return res;
}
int query_path(int u,int v)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res=(res+query(1,id[top[u]],id[u]))%mod;
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
res=(res+query(1,id[v],id[u]))%mod;
return res;
}
void modify_tree(int u,int k)
{
modify(1,id[u],id[u]+sz[u]-1,k);
}
int query_tree(int u)
{
return query(1,id[u],id[u]+sz[u]-1);
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>m>>root>>mod;
for(int i=1;i<=n;i++) cin>>w[i],w[i]%=mod;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs1(root,-1,1);
dfs2(root,root);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op,x,y,k;
cin>>op>>x;
if(op==1)
{
cin>>y>>k;
modify_path(x,y,k);
}else if(op==2)
{
cin>>y;
cout<<query_path(x,y)<<'\n';
}else if(op==3)
{
cin>>k;
modify_tree(x,k);
}else {
cout<<query_tree(x)<<'\n';
}
}
}
P3178 树上操作
树链剖分模板
稍微修改一下就可以通过
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,m;
int h[N],e[N<<1],ne[N<<1],idx;
int dep[N],top[N],id[N],cnt,fa[N],son[N],sz[N],w[N],nw[N];
struct node
{
int add,sum;
int l,r;
}tr[N<<4];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int depth)
{
dep[u]=depth,fa[u]=f;
sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++cnt,nw[cnt]=w[u];
if(!son[u]) return ;
dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void pushup(int u)
{
tr[u].sum=(tr[u<<1].sum+tr[u<<1|1].sum);
}
void pushdown(int u)
{
if(tr[u].add)
{
tr[u<<1].add+=tr[u].add,tr[u<<1|1].add+=tr[u].add;
tr[u<<1].sum+=tr[u].add*(tr[u<<1].r-tr[u<<1].l+1);
tr[u<<1|1].sum+=tr[u].add*(tr[u<<1|1].r-tr[u<<1|1].l+1);
tr[u].add=0;
}
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
if(l==r)
{
tr[u].add=0,tr[u].sum=nw[l];
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int k)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].add+=k,tr[u].sum=(tr[u].sum+k*(tr[u].r-tr[u].l+1));
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,k);
if(r>mid) modify(u<<1|1,l,r,k);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
return tr[u].sum;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
int res=0;
if(l<=mid) res=(res+query(u<<1,l,r));
if(r>mid) res=(res+query(u<<1|1,l,r));
return res;
}
int query_path(int u,int v)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res=(res+query(1,id[top[u]],id[u]));
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
res=(res+query(1,id[v],id[u]));
return res;
}
void modify_tree(int u,int k)
{
modify(1,id[u],id[u]+sz[u]-1,k);
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i];
memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op,x,k;
cin>>op>>x;
if(op==1)
{
cin>>k;
modify(1,id[x],id[x],k);
}else if(op==3)
{
cout<<query_path(x,1)<<'\n';
}else
{
cin>>k;
modify_tree(x,k);
}
}
}
P3128 Max Flow P
一条输送路径的两端点需要修改,最终查询点的最大值
可以用线段树维护,单点修改,区间查询
但是这道题有更简单的方法
树上差分
每次修改相当于在\(s\)和\(t\)上增加,在 \(lca\) 和\(fa[lca]\)上删除
所以这道题中树链剖分起到求\(lca\)的作用
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e4+10,M=1e5+10;
int h[N],e[M],ne[M],idx;
int n,k,stp;
int s[N];
int dep[N],fa[N],top[N],son[N],id[N],sz[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int deep)
{
fa[u]=f,dep[u]=deep,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,deep+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t,id[u]=++stp;
if(son[u]) dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==son[u]||v==fa[u]) continue;
dfs2(v,v);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
return v;
}
int dfs3(int u)
{
int ans=0;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]) continue;
ans=max(ans,dfs3(v));
s[u]+=s[v];
}
return max(ans,s[u]);
}
signed main()
{
cin>>n>>k;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,0,1);
dfs2(1,1);
for(int i=1;i<=k;i++)
{
int u,v;
cin>>u>>v;
int l=lca(u,v);
s[u]++,s[v]++;
s[l]--,s[fa[l]]--;
}
cout<<dfs3(1)<<endl;
}
P3258 松鼠的新家
从 \(a_i\) 走到 \(a_{i+1}\),需要将路径上所有点 \(+1\)
用树上差分维护点权
代码和上一道几乎一样,但注意处理边界情况,把重复的减去
这里给出一个倍增求\(lca\)的做法
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+10,M=6e5+10;
int n;
int q[N],fa[N][31],num[N],dep[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int f)
{
fa[u][0]=f,dep[u]=dep[f]+1;
for(int i=1;i<=30;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs(v,u);
}
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
for(int i=30;i>=0;i--)
{
if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
}
if(v==u) return v;
for(int i=30;i>=0;i--)
{
if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
}
return fa[v][0];
}
void query(int u,int f)
{
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
query(v,u);
num[u]+=num[v];
}
}
signed main()
{
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) cin>>q[i];
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs(1,0);
for(int i=2;i<=n;i++)
{
int u=q[i-1],v=q[i];
int t=lca(u,v);
num[fa[t][0]]--;
num[t]--;
num[u]++;
num[v]++;
}
query(1,0);
for(int i=2;i<=n;i++) num[q[i]]--;
for(int i=1;i<=n;i++) cout<<num[i]<<'\n';
}
P2146 软件包管理器
安装 就相当于查询并修改 \(x\) 到根的路径上有几个点未添加
卸载就相当于查询并修改以 \(x\) 为根的子树中有几个点已经添加
可以用树链剖分+线段树维护
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,q;
vector<int> e[N];
int fa[N];
int top[N],son[N],cnt;
int dep[N],id[N],sz[N];
struct noe
{
int l,r;
int sum,add;
}tr[N<<2];
void dfs1(int u,int f,int depth)
{
sz[u]=1,dep[u]=depth;
// id[u]=++cnt;
son[u]=n+1;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++cnt;
if(son[u]==n+1) return ;
dfs2(son[u],t);
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void pushdown(int u)
{
if(tr[u].add!=0)
{
tr[u<<1].add=tr[u].add,tr[u<<1].sum=max((int)0,(tr[u<<1].r-tr[u<<1].l+1)*tr[u].add);
tr[u<<1|1].add=tr[u].add,tr[u<<1|1].sum=max((tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].add,(int)0);
tr[u].add=0;
}
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
tr[u].add=0,tr[u].sum=0;
if(l==r)
{
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
void modify(int u,int l,int r,int k)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
if(k==1)
tr[u].add=1,tr[u].sum=tr[u].r-tr[u].l+1;
else tr[u].add=-1,tr[u].sum=0;
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,k);
if(r>mid) modify(u<<1|1,l,r,k);
pushup(u);
}
int query(int u,int l,int r,int x)
{
if(tr[u].l>=l&&tr[u].r<=r) {
// if(x==1) cout<<tr[u].l<<' '<<tr[u].r<<' '<<tr[u].sum<<endl;
if(x==1) return tr[u].sum;//有几个点被安装了
else return (tr[u].r-tr[u].l+1-tr[u].sum);//没被安装的数量
}
pushdown(u);
int res=0;
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) res+=query(u<<1,l,r,x);
if(r>mid) res+=query(u<<1|1,l,r,x);
// if(x==1) cout<<res<<endl;
return res;
}
int query_path(int v,int u)
{
if(query(1,id[u],id[u],1)==1) return 0;
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res+=query(1,id[top[u]],id[u],0);//路径上没加过的点
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
res+=query(1,id[v],id[u],0);
// cout<<u<<' '<<v<<' '<<id[u]<<' '<<id[v]<<endl;
return res;
}
int query_tree(int u)
{
return query(1,id[u],id[u]+sz[u]-1,1);
}
void modify_path(int v,int u)
{
if(query(1,id[u],id[u],1)==1) return ;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify(1,id[top[u]],id[u],1);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
modify(1,id[v],id[u],1);
}
void modify_tree(int u)
{
modify(1,id[u],id[u]+sz[u]-1,-1);
}
signed main()
{
cin>>n;
for(int i=1;i<n;i++)
{
cin>>fa[i];
e[fa[i]].push_back(i);
}
dfs1(0,-1,1);
dfs2(0,0);
build(1,1,n);
// for(int i=0;i<=n-1;i++) cout<<id[i]<<' ';
cin>>q;
for(int i=1;i<=q;i++)
{
string op;
int u;
cin>>op>>u;
if(op=="install")
{
cout<<query_path(0,u)<<endl;
modify_path(0,u);
}else {
cout<<query_tree(u)<<endl;
modify_tree(u);
}
}
}
P3313 旅行
树剖+动态开点线段树
以不同宗教为根,建立线段树
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int n,q;
int w[N],c[N];
int h[N],e[N<<1],ne[N<<1],idx;
int dep[N],id[N],cnt,sz[N],fa[N],son[N],top[N];
int root[N],tot;
struct node
{
int l,r;
int sum,maxn;
}tr[20000002];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int depth)
{
fa[u]=f,dep[u]=depth,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++cnt;
if(!son[u]) return ;
dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void modify(int &u,int l,int r,int w,int pos)
{
if(!u) u=++tot;
tr[u].maxn=max(tr[u].maxn,w);
tr[u].sum+=w;
if(l==r) return ;
int mid=l+r>>1;
if(pos<=mid) modify(tr[u].l,l,mid,w,pos);
else modify(tr[u].r,mid+1,r,w,pos);
}
void pushup(int u)
{
tr[u].maxn=max(tr[tr[u].l].maxn,tr[tr[u].r].maxn);
tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum;
return ;
}
void remove(int u,int l,int r,int w,int pos)
{
if(l==r) {
tr[u].maxn=0,tr[u].sum=0;
return ;
}
int mid=l+r>>1;
if(pos<=mid) remove(tr[u].l,l,mid,w,pos);
else remove(tr[u].r,mid+1,r,w,pos);
pushup(u);
}
int query1(int u,int L,int R,int l,int r)
{
if(L>=l&&R<=r) return tr[u].sum;
int mid=L+R>>1;
int res=0;
if(l<=mid) res+=query1(tr[u].l,L,mid,l,r);
if(r>mid) res+=query1(tr[u].r,mid+1,R,l,r);
return res;
}
int query2(int u,int L,int R,int l,int r)
{
if(L>=l&&R<=r) return tr[u].maxn;
int mid=L+R>>1;
int res=0;
if(l<=mid) res=max(res,query2(tr[u].l,L,mid,l,r));
if(r>mid) res=max(res,query2(tr[u].r,mid+1,R,l,r));
return res;
}
int query_sum(int u,int v,int c)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res+=query1(root[c],1,n,id[top[u]],id[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
res+=query1(root[c],1,n,id[v],id[u]);
return res;
}
int query_max(int u,int v,int c)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
res=max(res,query2(root[c],1,n,id[top[u]],id[u]));
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
res=max(res,query2(root[c],1,n,id[v],id[u]));
return res;
}
signed main()
{
cin>>n>>q;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs1(1,-1,1);
dfs2(1,1);
for(int i=1;i<=n;i++)
{
modify(root[c[i]],1,n,w[i],id[i]);
}
for(int i=1;i<=q;i++)
{
string op;
int x,y;
cin>>op>>x>>y;
if(op=="CC")
{
remove(root[c[x]],1,n,w[x],id[x]);
modify(root[y],1,n,w[x],id[x]);
c[x]=y;
}else if(op=="CW")
{
remove(root[c[x]],1,n,w[x],id[x]);
modify(root[c[x]],1,n,y,id[x]);
w[x]=y;
}
else if(op=="QS")
{
cout<<query_sum(x,y,c[x])<<endl;
}else {
cout<<query_max(x,y,c[x])<<endl;
}
}
}
CF1062E Company
用线段树维护区间 \(dfs\) 序最大、次大、最小、次小值
树剖求 \(lca\),再进行比较选择最优解
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int dfn[N],id[N],stp,dep[N],son[N],sz[N],top[N];
int fa[N];
vector<int> e[N];
struct lyw
{
int l,r;
int a1,a2,b1,b2;//最大,次大,最小,次小
}tr[N<<2];
void pushup(lyw &a,lyw b,lyw c)
{
if(b.a1>c.a1)
{
a.a1=b.a1;
a.a2=max(b.a2,c.a1);
}else {
a.a1=c.a1;
a.a2=max(b.a1,c.a2);
}
if(b.b1<c.b1)
{
a.b1=b.b1;
a.b2=min(b.b2,c.b1);
}else {
a.b1=c.b1;
a.b2=min(b.b1,c.b2);
}
}
void dfs1(int u,int d)
{
dep[u]=d;
sz[u]=1;
for(auto v:e[u])
{
dfs1(v,d+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
dfn[u]=++stp;
id[stp]=u;
if(son[u]) dfs2(son[u],t);
for(auto v:e[u])
{
if(v==son[u]) continue;
dfs2(v,v);
}
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
if(l==r)
{
tr[u].a1=tr[u].b1=dfn[l];
tr[u].a2=0;
tr[u].b2=n+1;
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
lyw query(int u,int l,int r)
{
if(tr[u].r<l||tr[u].l>r) return (lyw){0,0,0,0,n+1,n+1};
if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
int mid=l+r>>1;
lyw ans;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else {
pushup(ans,query(u<<1,l,r),query(u<<1|1,l,r));
return ans;
}
}
int lca(int u,int v)
{
if(u==0||v==0) return 0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) v=fa[top[v]];
else u=fa[top[u]];
}
if(dep[u]<dep[v]) return u;
else return v;
}
signed main()
{
cin>>n>>m;
for(int i=2;i<=n;i++)
{
cin>>fa[i];
e[fa[i]].push_back(i);
}
fa[1]=0;
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int l,r;
cin>>l>>r;
if(l==r-1)
{
if(dep[l]>dep[r]) cout<<r<<' '<<dep[l]<<'\n';
else cout<<l<<' '<<dep[r]<<'\n';
continue;
}
lyw w=query(1,l,r);
int l1=lca(id[w.a1],id[w.b2]);
int l2=lca(id[w.b1],id[w.a2]);
if(dep[l1]<dep[l2]) cout<<id[w.a1]<<' '<<dep[l2]<<'\n';
else cout<<id[w.b1]<<' '<<dep[l1]<<'\n';
}
}
P6071 Treequery
上一个问题的加强版
针对 \(p\) 和 \(lca\) 的位置关系分类讨论
主席树 \(+\) 树链剖分
- 调试警告:大数据TLE了,可能是数组开小了
详细题解见这里
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50,M=4e5+10;
int n,q;
int h[N],e[M],ne[M],w[M],idx;
int fa[N],sum[N],sz[N],dep[N],son[N],top[N],num[N],id[N],stp,tot;
int lc[N*40],rc[N*40],root[N];
int a[N<<2];
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int addtr(int pre,int l,int r,int x)
{
int o=++tot;
if(l<r)
{
int mid=l+r>>1;
if(x<=mid) lc[o]=addtr(lc[pre],l,mid,x),rc[o]=rc[pre];
else lc[o]=lc[pre],rc[o]=addtr(rc[pre],mid+1,r,x);
}
return o;
}
int merge(int u,int v,int l,int r)
{
if(!u||!v) return u|v;
int o=++tot;
if(l<r)
{
int mid=l+r>>1;
lc[o]=merge(lc[u],lc[v],l,mid);
rc[o]=merge(rc[u],rc[v],mid+1,r);
}
return o;
}
bool ask(int u,int l,int r,int L,int R)
{
if(!u) return 0;
int mid=L+R>>1;
if(l<=L&&r>=R) return 1;
if(l<=mid&&ask(lc[u],l,r,L,mid)) return 1;
else return r>mid&&ask(rc[u],l,r,mid+1,R);
}
void dfs1(int u,int f)
{
sz[u]=1,fa[u]=f,dep[u]=dep[f]+1;
root[u]=addtr(0,1,n,u);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
sum[v]=sum[u]+w[i];
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
root[u]=merge(root[u],root[v],1,n);
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++stp,num[stp]=u;
if(son[u]) dfs2(son[u],t);
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) v=fa[top[v]];
else u=fa[top[u]];
}
if(dep[u]<dep[v]) return u;
else return v;
}
void build(int u,int l,int r)
{
if(l==r)
{
a[u]=l;
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
a[u]=lca(a[u<<1],a[u<<1|1]);
}
int query(int u,int l,int r,int L,int R)
{
if(l<=L&&r>=R) return a[u];
int mid=L+R>>1;
if(r<=mid) return query(u<<1,l,r,L,mid);
else if(l>mid) return query(u<<1|1,l,r,mid+1,R);
else return lca(query(u<<1,l,r,L,mid),query(u<<1|1,l,r,mid+1,R));
}
int getfa(int u,int x,int y)
{
while(u)
{
if(ask(root[top[u]],x,y,1,n))
{
int l=id[top[u]],r=id[u];
while(l<r)
{
int mid=l+r+1>>1;
if(ask(root[num[mid]],x,y,1,n)) l=mid;
else r=mid-1;
}
return num[l];
}
u=fa[top[u]];
}
}
signed main()
{
cin>>n>>q;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++)
{
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
int ans=0;
while(q--)
{
int p,l,r;
cin>>p>>l>>r;
p^=ans,l^=ans,r^=ans;
int u=query(1,l,r,1,n),v;
if(id[u]>=id[p]&&id[u]<=id[p]+sz[p]-1) ans=sum[u]-sum[p];
else if(ask(root[p],l,r,1,n)) ans=0;
else if(id[v=getfa(p,l,r)]>=id[u]&&id[v]<=id[u]+sz[u]-1) ans=sum[p]-sum[v];
else ans=sum[p]+sum[u]-sum[v]*2;
cout<<ans<<'\n';
}
}
P4211 LCA
暴力不难写出,重点在于如何优化
注意到 \(lca\) 一定在 \(z\) 到根节点的路径上,所以通过 \(1-z\) 统计答案
对于点 \(x\),如果将 \(x\) 到根节点的路径上的点权全 \(+1\),每个点到根的 \(dep\) 就等于这个点到根节点路径上所有点的和
注意到这个性质,就可以差分求解了
树链剖分+线段树+差分
总时间复杂度\(O(nlog^2n)\)
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+10,M=1e5+10,mod=201314;
int n,m,cnt;
int fa[N];
int h[N],ne[M],e[M],idx;
int dep[N],sz[N],son[N],top[N],id[N],stp;
int ans[N];
struct que
{
int id,type;
int u,z;
bool operator<(const que &W) const
{
return u<W.u;
}
}q[M];
struct lyw
{
int l,r,sum,add;
}tr[N<<2];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int d)
{
dep[u]=d,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]) continue;
dfs1(v,d+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t,id[u]=++stp;
if(son[u]) dfs2(son[u],t);
else return ;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r,tr[u].sum=tr[u].add=0;
if(l==r)
{
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}
void pushdown(int u)
{
if(tr[u].add)
{
tr[u<<1].add+=tr[u].add,tr[u<<1|1].add+=tr[u].add;
tr[u<<1].sum+=tr[u].add*(tr[u<<1].r-tr[u<<1].l+1);
tr[u<<1|1].sum+=tr[u].add*(tr[u<<1|1].r-tr[u<<1|1].l+1);
tr[u].add=0;
}
}
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void modify(int u,int l,int r)
{
if(l<=tr[u].l&&r>=tr[u].r)
{
tr[u].add++;
tr[u].sum+=(tr[u].r-tr[u].l+1);
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r);
if(r>mid) modify(u<<1|1,l,r);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
return tr[u].sum;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
int res=0;
if(l<=mid) res+=query(u<<1,l,r);
if(r>mid) res+=query(u<<1|1,l,r);
return res;
}
void modify_path(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify(1,id[top[u]],id[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
modify(1,id[v],id[u]);
}
int query_path(int u,int v)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
(res+=query(1,id[top[u]],id[u]))%=mod;
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
(res+=query(1,id[v],id[u]))%=mod;
return res;
}
signed main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=2;i<=n;i++)
{
cin>>fa[i];
fa[i]++;
add(i,fa[i]);
add(fa[i],i);
}
dfs1(1,1);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int l,r,z;
cin>>l>>r>>z;
l++,r++,z++;
q[++cnt]={i,-1,l-1,z};
q[++cnt]={i,1,r,z};
}
sort(q+1,q+1+cnt);
for(int i=1,x=0;i<=cnt;i++)
{
while(x<q[i].u)
{
x++;
modify_path(1,x);
}
ans[q[i].id]+=(q[i].type*query_path(1,q[i].z));
}
for(int i=1;i<=m;i++) cout<<(ans[i]+mod)%mod<<'\n';
}
P4216 情报传递
可以清楚查询操作相当于询问\(x-y\)路径上有几个点\(t<now-z+1\)
可以考虑把这个问题离线,按时间从小到大插入和查询
用树状数组查询树上差分
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,m,root,cnt;
int fa[N],dep[N],ne[N<<1],e[N<<1],h[N],idx;
int son[N],sz[N],id[N],stp,top[N];
int ans1[N],ans2[N];
int tr[N];
struct lyw
{
int id,type,t,x,y;
bool operator<(const lyw &W) const
{
if(t!=W.t)
return t<W.t;
return type>W.type;//先插入,后查询
}
}q[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int d)
{
dep[u]=d,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]) continue;
dfs1(v,d+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t,id[u]=++stp;
if(son[u]) dfs2(son[u],t);
else return ;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
int lowbit(int x)
{
return x&(-x);
}
void Add(int x,int c)
{
for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
int query(int x)
{
int res=0;
for(int i=x;i>=1;i-=lowbit(i)) res+=tr[i];
return res;
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if(dep[u]<dep[v]) return u;
else return v;
}
void Query(int u,int v,int o)
{
int l=lca(u,v);
ans1[o]=dep[u]+dep[v]-dep[l]*2+1;
ans2[o]=query(id[u])+query(id[v])-query(id[l])-query(id[fa[l]]);
}
signed main()
{
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)
{
cin>>fa[i];
if(fa[i]==0) root=i;
else add(i,fa[i]),add(fa[i],i);
}
dfs1(root,1);
dfs2(root,root);
cin>>m;
for(int i=1;i<=m;i++)
{
int op;
cin>>op;
if(op==2)
{
int x;
cin>>x;
q[i]={i,2,i,x,0};
}else {
int x,y,z;
cin>>x>>y>>z;
q[i]={i,1,i-z-1,x,y};
}
}
sort(q+1,q+1+m);
for(int i=1;i<=m;i++)
{
if(q[i].type==2)
{
Add(id[q[i].x],1);
Add(id[q[i].x]+sz[q[i].x],-1);
}else {
Query(q[i].x,q[i].y,q[i].id);
}
}
for(int i=1;i<=m;i++)
if(ans1[i]||ans2[i]) cout<<ans1[i]<<' '<<ans2[i]<<'\n';
}
P2486 染色
树链剖分+线段树
在线段树上储存段数,最左边的颜色,最右边的颜色,是否被修改过
路径上操作需要额外特判有没有可以合并的
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int w[N],id[N],nw[N],dep[N],fa[N],top[N],son[N],sz[N],stp;
int e[N<<1],ne[N<<1],h[N],idx;
struct lyw
{
int l,r;
int sum,lc,rc,tag;
}tr[N<<2];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int d)
{
dep[u]=d,fa[u]=f,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,d+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t,id[u]=++stp,nw[stp]=w[u];
if(son[u]) dfs2(son[u],t);
else return ;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void pushup(lyw &a,lyw b,lyw c)
{
a.sum=b.sum+c.sum;
if(b.rc==c.lc) a.sum--;
a.lc=b.lc,a.rc=c.rc;
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
if(l==r)
{
tr[u].sum=1,tr[u].lc=tr[u].rc=nw[l];
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void pushdown(int u)
{
if(tr[u].tag)
{
tr[u<<1].tag=tr[u<<1|1].tag=tr[u].tag;
tr[u<<1].sum=tr[u<<1|1].sum=1;
tr[u<<1].lc=tr[u<<1|1].lc=tr[u].lc;
tr[u<<1].rc=tr[u<<1|1].rc=tr[u].rc;
tr[u].tag=0;
}
}
void modify(int u,int l,int r,int val)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].tag=val;
tr[u].sum=1,tr[u].lc=tr[u].rc=val;
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,val);
if(r>mid) modify(u<<1|1,l,r,val);
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
lyw query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else {
lyw res;
pushup(res,query(u<<1,l,r),query(u<<1|1,l,r));
return res;
}
}
void modify_path(int u,int v,int c)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify(1,id[top[u]],id[u],c);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
modify(1,id[v],id[u],c);
}
int query_path(int u,int v)
{
int ans1=-1,ans2=-1,ans=0;
lyw c;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v),swap(ans1,ans2);
c=query(1,id[top[u]],id[u]);
ans+=c.sum;
if(ans1==c.rc) ans--;
ans1=c.lc;
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v),swap(ans1,ans2);
c=query(1,id[v],id[u]);
ans+=c.sum;
if(ans1==c.rc) ans--;
if(ans2==c.lc) ans--;
return ans;
}
signed main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<n;i++) {
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,1,1);
dfs2(1,1);
build(1,1,n);
// for(int i=1;i<=n;i++)
// modify(1,id[i],id[i],w[i]);
for(int i=1;i<=m;i++)
{
char op;
int a,b,c;
cin>>op>>a>>b;
if(op=='C')
{
cin>>c;
modify_path(a,b,c);
}else
{
cout<<query_path(a,b)<<'\n';
}
}
}
P7735 轻重边
这道题的转化真的太妙了
建议好好思考一下再看题解
把改变边的状态,转化成改变点权
这样问题就转化成了
重边\(->\) 两端点权相同
轻边\(->\) 两端点权不同
每次修改给点权附一个独\(one\)无\(two\)的数
查询\(->\) 路径上有多少值相同的相邻点对
\(by\) \(the\) \(way\) 这道题可以用染色的代码直接改
这题稍微有一点点卡常,记得开输入输出优化
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int id[N],dep[N],fa[N],top[N],son[N],sz[N],stp;
int e[N<<1],ne[N<<1],h[N],idx;
struct lyw
{
int l,r;
int sum,lc,rc,tag;
}tr[N<<2];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int f,int d)
{
dep[u]=d,fa[u]=f,sz[u]=1;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==f) continue;
dfs1(v,u,d+1);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t,id[u]=++stp;
if(son[u]) dfs2(son[u],t);
else return ;
for(int i=h[u];~i;i=ne[i])
{
int v=e[i];
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
void pushup(lyw &a,lyw b,lyw c)
{
a.sum=b.sum+c.sum;
if(b.rc==c.lc&&b.rc>0) a.sum++;
a.lc=b.lc,a.rc=c.rc;
}
void build(int u,int l,int r)
{
tr[u].l=l,tr[u].r=r;
tr[u].tag=-1;
if(l==r)
{
tr[u].sum=0,tr[u].lc=tr[u].rc=-u;
return ;
}
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void pushdown(int u)
{
if(tr[u].tag!=-1)
{
tr[u<<1].tag=tr[u<<1|1].tag=tr[u].tag;
tr[u<<1].sum=tr[u<<1].r-tr[u<<1].l;
tr[u<<1|1].sum=tr[u<<1|1].r-tr[u<<1|1].l;
tr[u<<1].lc=tr[u<<1|1].lc=tr[u].tag;
tr[u<<1].rc=tr[u<<1|1].rc=tr[u].tag;
tr[u].tag=-1;
}
}
void modify(int u,int l,int r,int val)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].tag=val;
tr[u].sum=tr[u].r-tr[u].l,tr[u].lc=tr[u].rc=val;
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,val);
if(r>mid) modify(u<<1|1,l,r,val);
pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
lyw query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u];
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1,l,r);
else if(l>mid) return query(u<<1|1,l,r);
else {
lyw res;
pushup(res,query(u<<1,l,r),query(u<<1|1,l,r));
return res;
}
}
void modify_path(int u,int v,int c)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify(1,id[top[u]],id[u],c);
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v);
modify(1,id[v],id[u],c);
}
int query_path(int u,int v)
{
int ans1=-1,ans2=-1,ans=0;
lyw c;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v),swap(ans1,ans2);
c=query(1,id[top[u]],id[u]);
ans+=c.sum;
if(ans1==c.rc&&ans1>0) ans++;
ans1=c.lc;
u=fa[top[u]];
}
if(dep[u]<dep[v]) swap(u,v),swap(ans1,ans2);
c=query(1,id[v],id[u]);
ans+=c.sum;
if(ans1==c.rc&&ans1>0) ans++;
if(ans2==c.lc&&ans2>0) ans++;
return ans;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--){
cin>>n>>m;
memset(h,-1,sizeof h);
memset(fa,0,sizeof fa);
memset(son,0,sizeof son);
idx=0,stp=0;
for(int i=1;i<n;i++) {
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(1,1,1);
dfs2(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op;
int a,b;
cin>>op>>a>>b;
if(op==1)
{
modify_path(a,b,i);
}else
{
cout<<query_path(a,b)<<'\n';
}
}
}
}
浙公网安备 33010602011771号