思路:
求出集合
A
A
A和集合
B
B
B可达点的交集,集合
C
C
C的前驱节点的并集。两集合取交集即可。
题目保证所有节点可达
1
1
1号点。
A
A
A集合所有点到
1
1
1的路径和
B
B
B集合所有点到
1
1
1的路径的公共点即为两集合公共可达点。
C
C
C集合所有点的子树的并集即为所有前驱节点。 (可以自行画图)
对树的路径修改直接上树剖。
区间打标记最后查询同时存在三个标记的点即可。(2进制压位的做法如果最后整个区间去递归并最值优化 这个可以被卡)
三种区间每种区间合并,最后取并集即可。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
vector<int> ve[N];
// 预处理
int dep[N],fa[N],son[N],_size[N];
void dfs1(int now,int last){
dep[now]=dep[last]+1; fa[now]=last;
int maxn=0; _size[now]=1;
for(auto it:ve[now]){
if(it==last) continue;
dfs1(it,now);
if(_size[it]>maxn){
maxn=_size[it];
son[now]=it;
}
_size[now]+=_size[it];
}
}
// 树剖
int top[N],dfn[N],ti=0;
void dfs2(int now,int topf){
dfn[now]=++ti,top[now]=topf;
if(son[now]==0){
return ;
}
dfs2(son[now],topf);
for(auto it:ve[now]){
if(it==son[now]||it==fa[now]) continue;
dfs2(it,it);
}
}
// 修改路径
void modify(int x,int y,vector< pair<int,int> > &pos){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]){
swap(x,y);
}
pos.push_back({dfn[top[x]],dfn[x]});
x=fa[top[x]];
}
if(dfn[x]>dfn[y]){
swap(x,y);
}
pos.push_back({dfn[x],dfn[y]});
}
// 区间合并
void work(vector< pair<int,int> > &pos){
sort(pos.begin(),pos.end());
vector< pair<int,int> > res;
int l=-inf,r=-inf;
for(auto it:pos){
if(r<it.first){
if(l!=-inf){
res.push_back({l,r});
}
l=it.first,r=it.second;
}
else{
r=max(r,it.second);
}
}
if(l!=-inf){
res.push_back({l,r});
}
pos=res;
}
// 区间求交
void solve(vector< pair<int,int> > &A,vector< pair<int,int> > &B,vector< pair<int,int> > &C){
int idxa=0,idxb=0,idxc=0,ans=0,l=0,r=0;
int sa=A.size(),sb=B.size(),sc=C.size();
while(idxa<sa&&idxb<sb&&idxc<sc){
while(idxa<sa&&A[idxa].second<=l){
idxa++;
}
while(idxb<sb&&B[idxb].second<=l){
idxb++;
}
while(idxc<sc&&C[idxc].second<=l){
idxc++;
}
if(idxa>=sa||idxb>=sb||idxc>=sc){
break;
}
l=max({A[idxa].first,B[idxb].first,C[idxc].first});
r=min({A[idxa].second,B[idxb].second,C[idxc].second});
ans+=max(0,r-l+1);
l=r;
}
cout<<ans<<endl;
}
int main(){
guo312;
int t; cin>>t;
while(t--){
int n,q; cin>>n>>q;
for(int i=2;i<=n;i++){
ve[i].clear();
}
for(int i=2;i<=n;i++){
int v; cin>>v;
ve[i].push_back(v);
ve[v].push_back(i);
}
dfs1(1,0); dfs2(1,1);
while(q--){
int sa,sb,sc; cin>>sa>>sb>>sc;
vector< pair<int,int> > A;
vector< pair<int,int> > B;
vector< pair<int,int> > C;
for(int i=1;i<=sa;i++){
int pos; cin>>pos;
modify(1,pos,A);
}
for(int i=1;i<=sb;i++){
int pos; cin>>pos;
modify(1,pos,B);
}
for(int i=1;i<=sc;i++){
int pos; cin>>pos;
C.push_back({dfn[pos],dfn[pos]+_size[pos]-1});
}
work(A),work(B),work(C);
solve(A,B,C);
}
}
return 0;
}