虚树大小可以从两个角度进行思考:

最小斯坦纳树大小,或者,子树内至少有一个标记点的点的数量减去虚树上边的点的数量。

前者的优点是简洁,后者的优点是不依赖 dfn 序的排序。

这道题在利用后者的同时,将赋值看作了颜色段,用树链剖分保证了颜色段总数为 \(O(n\log n)\),利用了 odt。


#include<bits/stdc++.h> 
using namespace std;
#define N 100005
struct node{
	int l,r;mutable int c;
	bool operator < (const node &x)const{return l<x.l;}
	node(int x,int y,int z){l=x;r=y;c=z;}
};
set<node> odt;
vector<int> G[N];
vector< pair<int,int> > qry[N];
pair<int,int> mn[N][20],mx[N][20];
int n,m,q,tot,a[N],fa[N],siz[N],dis[N],go[N][20],son[N],dfn[N],top[N],ans[N];
void dfs(int u,int d){
	go[u][0]=fa[u]=d;siz[u]=1;dis[u]=dis[d]+1;
	for(int i=1;(go[u][i]=go[go[u][i-1]][i-1]);i++);
	for(int v:G[u])if(v^d)
		dfs(v,u),siz[u]+=siz[v],son[u]=siz[son[u]]<siz[v]?v:son[u];
}
void dfs2(int u,int t){
	top[u]=t;dfn[u]=++tot;
	if(son[u])dfs2(son[u],t);
	for(int v:G[u])if((v^fa[u])&&(v^son[u]))
		dfs2(v,v);
}
int lca(int u,int v){
	if(dis[u]<dis[v])swap(u,v);
	for(int i=19;i>=0;i--)if(dis[go[u][i]]>=dis[v])u=go[u][i];
	if(u==v)return u;
	for(int i=19;i>=0;i--)if(go[u][i]!=go[v][i])u=go[u][i],v=go[v][i];
	return go[u][0];
}
int sum=0;
namespace bit{
	int tr[N];
	void add(int x,int y){sum+=y;++x;for(int i=x;i<=m+1;i+=(i&-i))tr[i]+=y;}
	int ask(int x){++x;int ans=0;for(int i=x;i;i-=(i&-i))ans+=tr[i];return ans;}
}
auto split(int x){
	if(x>n)return odt.end();
	auto it=--odt.upper_bound(node{x,0,0});
	if(it->l==x)return it;
	int l=it->l,r=it->r,c=it->c;
	odt.erase(it);odt.insert({l,x-1,c});
	return odt.insert(node{x,r,c}).first;
}
void assign(int l,int r,int c){
	auto itr=split(r+1),itl=split(l);
	for(auto it=itl;it!=itr;it++)
		bit::add(it->c,-(it->r)+(it->l)-1);
	bit::add(c,r-l+1);
	odt.erase(itl,itr);
	odt.insert(node{l,r,c});
}
int qrymn(int l,int r){
	int k=__lg(r-l+1);
	return min(mn[l][k],mn[r-(1<<k)+1][k]).second;
}
int qrymx(int l,int r){
	int k=__lg(r-l+1);
	return max(mx[l][k],mx[r-(1<<k)+1][k]).second;
}
int main(){
	scanf("%d%d%d",&n,&m,&q);
	for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),G[u].push_back(v),G[v].push_back(u);
	for(int i=1;i<=m;i++)scanf("%d",&a[i]);
	for(int i=1,l,r;i<=q;i++)scanf("%d%d",&l,&r),qry[r].push_back({l,i});
	dfs(1,0);dfs2(1,1);
	odt.insert({1,n,0});bit::add(0,n);
	for(int i=1;i<=m;i++)mn[i][0]={dfn[a[i]],a[i]},mx[i][0]={dfn[a[i]],a[i]};
	for(int k=1;k<=19;k++)for(int i=1;i+(1<<k)-1<=m;i++)
		mx[i][k]=max(mx[i][k-1],mx[i+(1<<k-1)][k-1]),
		mn[i][k]=min(mn[i][k-1],mn[i+(1<<k-1)][k-1]);
	for(int i=1;i<=m;i++){
		int u=a[i];
		while(u){
			assign(dfn[top[u]],dfn[u],i);
			u=fa[top[u]];
		}
		for(auto [l,id]:qry[i])ans[id]=n-bit::ask(l-1)-dis[lca(qrymn(l,i),qrymx(l,i))]+1;
	}
	for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
}
/*
5 10 1
1 2
2 3
2 4
2 5
4 3 4 4 1 3 1 3 2 4 
7 7

*/