虚树大小可以从两个角度进行思考:
最小斯坦纳树大小,或者,子树内至少有一个标记点的点的数量减去虚树上边的点的数量。
前者的优点是简洁,后者的优点是不依赖 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
*/