这题的数据限制不难想到要套一个虚树.对于一个询问,我们先把包含所有关键点的虚树建出来,然后预处理虚树上每个点的最大覆盖范围,具体操作是一遍dfs由儿子更新父亲, 即(va_x=max(va_x,va_y-dis_{x,y})) ,第二遍dfs由父亲更新儿子.那么现在要解决两个问题:怎么统计一个点的贡献,怎么减掉算重的部分
先考虑只统计一个点的贡献,本能的想法是预处理出到某个点距离 (le) 某个值的点数.因为到某个点距离 (le) 某个值的那些点在树上是个连通块,所以建出点分树,然后预处理每个点在点分子树内深度 (le) 某个值的点数 (f_{x,j}) ,和这个点的点分子树在点分树上父亲的点分子树里的(到点分父亲)深度 (le) 某个值的点数 (g_{x,j}) ,每次从询问点开始跳点分树父亲,假设我们询问距离点 (u) 不超过 (l) 的点数,设当前点为 (x) ,上一个点为 (ls) ,那么 (x) 的贡献为 (f_{x,l-dis_{u,x}}-g_{ls,l-dis_{u,x}})
然后是关于算重部分,因为经过上面一个预处理,对于虚树上相邻两点,他们算重部分连通块的中心一定在这两个点之间,并且每两个点的算重部分和其他点没有关系,所以只要减去每两个点的算重部分即可.可以发现这部分也是距离一个点不超过某个值的一个连通块,可以用一样的方法统计
注意这个点可能在边上,所以把所有边当成点即可,同时读入的覆盖范围要乘2
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=114514;
LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
void adde(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int qto[N<<1],qnt[N<<1],qhd[N],qt=1;
void addq(int x,int y)
{
++qt,qto[qt]=y,qnt[qt]=qhd[x],qhd[x]=qt;
++qt,qto[qt]=x,qnt[qt]=qhd[y],qhd[y]=qt;
}
int n,lz,dfn[N],ti,fa[N][20],gfa[N],ps[N],gds[N][50],rt,nsz,mx,sz[N],de[N],dp[N],t1[N],t2[N];
bool cmp(int aa,int bb){return dfn[aa]<dfn[bb];}
void dfs1(int x)
{
dfn[x]=++ti;
for(int j=1;j<=lz;++j)
{
fa[x][j]=fa[fa[x][j-1]][j-1];
if(!fa[x][j]) break;
}
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==fa[x][0]) continue;
fa[y][0]=x,de[y]=de[x]+1,dfs1(y);
}
}
int glca(int x,int y)
{
if(de[x]<de[y]) swap(x,y);
for(int j=lz;~j;--j) if(de[fa[x][j]]>=de[y]) x=fa[x][j];
if(x==y) return x;
for(int j=lz;~j;--j) if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
return fa[x][0];
}
int gdis(int x,int y){return de[x]+de[y]-2*de[glca(x,y)];}
bool ban[N];
vector<int> f[N],g[N];
void fdrt(int x,int ffa)
{
int nv=0;
sz[x]=1,dp[x]=de[x];
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa||ban[y]) continue;
de[y]=de[x]+1,fdrt(y,x);
dp[x]=max(dp[x],dp[y]),sz[x]+=sz[y],nv=max(nv,sz[y]);
}
nv=max(nv,nsz-sz[x]);
if(nv<mx) mx=nv,rt=x;
}
void dfs2(int x,int ffa,int xx,int ln)
{
g[xx][ln]+=x<=n;
gds[x][++ps[x]]=ln;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ffa||ban[y]) continue;
dfs2(y,x,xx,ln+1);
}
}
int bui(int x)
{
mx=nsz+1,fdrt(x,0),x=rt,ban[x]=1;
de[x]=0,fdrt(x,0);
f[x].resize(t1[x]=dp[x]+1),f[x][0]=x<=n;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(ban[y]) continue;
nsz=sz[y];//少了这行又WA又T
int len=dp[y]+1,yy=bui(y);
t2[yy]=len,gfa[yy]=x;
g[yy].resize(t2[yy]),dfs2(y,x,yy,1);
for(int j=1;j<t2[yy];++j) f[x][j]+=g[yy][j],g[yy][j]+=g[yy][j-1];
}
for(int j=1;j<t1[x];++j) f[x][j]+=f[x][j-1];
ban[x]=0;
return x;
}
int cal(int x,int l)
{
if(l<0) return 0;
int xx=x,ls=0,ans=0;
for(int j=0;x;++j)
{
int nl=min(t1[x]-1,l-gds[xx][j]);
if(nl>=0) ans+=f[x][nl]-(t2[ls]?g[ls][min(t2[ls]-1,nl)]:0);
ls=x,x=gfa[x];
}
return ans;
}
int va[N],st[N],tp,sq[N],ts,ans;
void dd1(int x,int ffa)
{
for(int i=qhd[x];i;i=qnt[i])
{
int y=qto[i];
if(y==ffa) continue;
dd1(y,x),va[x]=max(va[x],va[y]-(de[y]-de[x]));
}
}
void dd2(int x,int ffa)
{
ans+=cal(x,va[x]);
for(int i=qhd[x];i;i=qnt[i])
{
int y=qto[i];
if(y==ffa) continue;
int ln=de[y]-de[x];
va[y]=max(va[y],va[x]-ln),nsz=sz[y],dd2(y,x);
int zl=va[x]>=va[y]?va[x]-(ln-(va[y]-va[x]))/2:va[y]-(ln-(va[x]-va[y]))/2;
int xx=y,rs=va[y]-zl;
for(int j=lz;~j;--j) if(rs>=(1<<j)) rs-=1<<j,xx=fa[xx][j];
ans-=cal(xx,zl);
}
}
int main()
{
n=rd(),lz=log2(n<<1);
for(int i=1;i<n;++i) adde(n+i,rd()),adde(n+i,rd());
nsz=n+n-1,rt=bui(1);
de[1]=1,dfs1(1);
memset(va,-1,sizeof(va));
int q=rd();
while(q--)
{
ts=rd();
for(int i=1;i<=ts;++i)
sq[i]=rd(),va[sq[i]]=rd()<<1;
sort(sq+1,sq+ts+1,cmp);
st[tp=1]=1;
for(int i=1+(sq[1]==1);i<=ts;++i)
{
int x=sq[i],lca=glca(x,st[tp]);
if(lca!=st[tp])
{
while(tp>1&&dfn[st[tp-1]]>=dfn[lca]) addq(st[tp],st[tp-1]),--tp;
while(dfn[st[tp]]>dfn[lca]) addq(st[tp],lca),--tp;
if(st[tp]!=lca) st[++tp]=lca;
}
st[++tp]=x;
}
while(tp>1) addq(st[tp],st[tp-1]),--tp;
dd1(1,0);
ans=0,dd2(1,0);
printf("%d
",ans);
while(qt>1) va[qto[qt]]=-1,qhd[qto[qt]]=0,--qt;
va[1]=-1,qhd[1]=0;
}
return 0;
}