如果这篇博客帮助到你,可以请我喝一杯咖啡~
CC BY-NC-SA 4.0 (除特别声明或转载文章外)
当树是条链时,询问即为区间顺序对数,所以这道题肯定是根号题。
我们考虑把这个问题转化为树上链查询,建出询问点集的虚树 $T$,设虚树根为 $rt$,答案即为 $\sum\limits_{u\in leaf(T)}f(rt,u)-\sum\limits_{u\in T\land u\notin leaf(T)}(s_u-1) f(rt,u)$,其中 $leaf(T)$ 表示虚树的所有叶子,$s_u$ 表示 $u$ 的儿子数,$f(a,b)$ 表示 $a$ 到 $b$ 这条链的答案,这样拆分后总询问数不会超过 $\sum (2t_i-1)$,且每个询问内两点都是祖先关系
下文中的 $m$ 均指拆分后的询问数。
由于询问数较多,所以我们考虑 $O(n\sqrt m)$ 的莫队算法,显然是要莫队二离的。先树分块,分块大小 $B=O(\frac n{\sqrt m})$,最好用 Top Cluster。
先考虑不在同一块内的询问,我们把询问按照上端点所在的块分类,把上端点在同一块内的询问按照下端点排序,直接在树上跑莫队。发现移动的时候的贡献是一个上下的路径中有多少个权值大于/小于 $a_i$,按照莫队二离的套路进行差分后要求的就是根到 $j$ 的路径上有多少个权值大于/小于 $a_i$,和普通莫队二离一样扫描线,就是 dfs 一遍,顺便用分块维护根到当前点路径上的边的权值。
对于在同一块内的询问,我们发现路径长度是 $O(B)$ 级别的,直接在上面说的 dfs 的时候顺便求出答案就好。
#include<iostream>
#include<vector>
#include<utility>
#include<tuple>
#include<algorithm>
#include<cmath>
using std::cin;
using std::cout;
std::vector<int> v[100010];
int n,a[100010],fa[100010],dfn[100010],rk[100010],dep[100010],dfx;
void dfs(int x){
dfn[rk[x]=++dfx]=fa[x],dep[x]=dep[fa[x]]+1;
for(auto u:v[x]) dfs(u);
}
namespace ST{
int mx[17][100010],lg[100010];
inline bool cmp(int x,int y){return dep[x]<dep[y];}
void init(){
for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++) mx[0][i]=dfn[i];
for(int i=1;i<17;i++)
for(int j=1;j+(1<<i)-1<=n;j++)
mx[i][j]=std::min(mx[i-1][j],mx[i-1][j+(1<<(i-1))],cmp);
}
inline int query(int l,int r){
int k=lg[r-l+1];
return std::min(mx[k][l],mx[k][r-(1<<k)+1],cmp);
}
}
inline int lca(int x,int y){
if(x==y) return x;
if(rk[x]>rk[y]) std::swap(x,y);
return ST::query(rk[x]+1,rk[y]);
}
long long ans[1000010];
namespace work{
int B,stk[100010],tp,c[100010],bel[100010],R[100010];
long long f1[100010],f2[100010],ans[2000010];
std::vector<std::tuple<int,int,int,int>> vec,p1[100010],p2[100010];
struct node{
int a,b,id;
node(int x,int y,int z):a(x),b(y),id(z){}
};
std::vector<node> q[100010];
inline void update(int i,int v){
for(;i<=n;i+=i&-i) c[i]+=v;
}
inline int query(int i){
int ans=0;
for(;i;i&=i-1) ans+=c[i];
return ans;
}
void dv(int x){
int k=tp,ct=0;
f1[x]=query(a[x]-1)+f1[fa[x]];
f2[x]=query(n)-query(a[x])+f2[fa[x]];
update(a[x],1);
for(auto u:v[x]){
dv(u);
stk[++tp]=u;
if(bel[u]) ++ct,bel[x]=bel[u];
}
update(a[x],-1);
if(x==1||ct>1||tp-k>=B) bel[x]=x,tp=k;
}
int s1[320],s2[100010];
inline void upd(int x,int v){
for(int i=bel[x];i<=bel[n];i++) s1[i]+=v;
for(int i=R[bel[x]];i>=x;i--) s2[i]+=v;
}
inline int que(int x){return s1[bel[x]-1]+s2[x];}
void solve(int x){
upd(a[x],1);
for(auto [d,b,id,v]:p1[x]){
long long u=0;
while(b!=d) u+=que(a[b]-1),b=fa[b];
ans[id]+=v*u;
}
for(auto [d,b,id,v]:p2[x]){
long long u=0;
while(b!=d) u+=s1[bel[n]]-que(a[b]),b=fa[b];
ans[id]+=v*u;
}
for(auto u:v[x]) solve(u);
upd(a[x],-1);
}
void work(){
B=sqrt(6)*n/sqrt(vec.size());
if(!B) B=1;
dv(1);
for(int i=vec.size()-1;~i;i--){
auto [a,b,c,d]=vec[i];
if(!bel[a]||dep[b]<=dep[bel[a]]) p1[a].emplace_back(a,b,i,-1),ans[i]+=f1[b]-f1[a];
else q[bel[a]].emplace_back(a,b,i);
}
for(int i=1;i<=n;i++)if(i==bel[i]){
std::sort(q[i].begin(),q[i].end(),[](node x,node y){return rk[x.b]<rk[y.b];});
int l=i,r=i;
for(auto [a,b,id]:q[i]){
if(r!=b){
int u=lca(r,b);
if(r!=u) ans[id]-=f1[r]-f1[u],p1[l].emplace_back(u,r,id,1);
if(b!=u) ans[id]+=f1[b]-f1[u],p1[l].emplace_back(u,b,id,-1);
r=b;
}
if(dep[l]>dep[a]) ans[id]-=f2[l]-f2[a],p2[r].emplace_back(a,l,id,1);
if(dep[l]<dep[a]) ans[id]+=f2[a]-f2[l],p2[r].emplace_back(l,a,id,-1);
l=a;
}
}
B=sqrt(n);
for(int i=1;i<=n;i++) bel[i]=(i-1)/B+1,R[bel[i]]=i;
solve(1);
for(int i=1;i<=n;i++)
for(int j=1,k=q[i].size();j<k;j++) ans[q[i][j].id]+=ans[q[i][j-1].id];
for(int i=vec.size()-1;~i;i--){
auto [a,b,c,d]=vec[i];
::ans[c]+=d*ans[i];
}
}
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(nullptr);
cin>>n,a[1]=1;
for(int i=2;i<=n;i++) cin>>fa[i]>>a[i],v[fa[i]].push_back(i);
dfs(1);
ST::init();
int m;
cin>>m;
for(int k=1;k<=m;k++){
static int cnt[100010];
int c;
cin>>c;
std::vector<int> v;
for(int i=1,x;i<=c;i++) cin>>x,v.push_back(x);
std::sort(v.begin(),v.end(),[](int x,int y){return rk[x]<rk[y];});
for(int i=v.size()-1;i;i--) v.push_back(lca(v[i],v[i-1]));
std::sort(v.begin(),v.end(),[](int x,int y){return rk[x]<rk[y];});
v.erase(std::unique(v.begin(),v.end()),v.end());
int u=v.front();
for(auto x:v) cnt[x]=0;
for(int i=v.size()-1;i;i--){
if(!cnt[v[i]]) work::vec.emplace_back(u,v[i],k,1);
else if(cnt[v[i]]>1) work::vec.emplace_back(u,v[i],k,-cnt[v[i]]+1);
++cnt[lca(v[i],v[i-1])];
}
}
work::work();
for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';
return 0;
}