There are NN boxes, indexed by a number from 11 to NN. Each box may (or not may not) be put into other boxes. These boxes together form a tree structure (or a forest structure, to be precise).
You have to answer a series of queries of the following form: given a list of indices of the boxes, find the total number of boxes that the list of boxes actually contain.
Consider, for example, the following five boxes.
-
If the query is the list “1”, then the correct answer is “5”, because box 1 contains all boxes.
-
If the query is the list “4 5”, then the correct answer is “2”, for boxes 4 and 5 contain themselves and nothing else.
-
If the query is the list “3 4”, then the correct answer is “2”.
-
If the query is the list “2 3 4”, then the correct answer is “4”, since box 2 also contains box 5.
-
If the query is the list “2”, then the correct answer is “3”, because box 2 contains itself and two other boxes.
Input
The first line contains the integer NN (1≤N≤2000001≤N≤200000), the number of boxes.
The second line contains NNintegers. The iith integer is either the index of the box which contains the iith box, or zero if the iith box is not contained in any other box.
The third line contains an integer QQ (1≤Q≤1000001≤Q≤100000), the number of queries. The following QQ lines will have the following format: on each line, the first integer MM(1≤M≤201≤M≤20) is the length of the list of boxes in this query, then MM integers follow, representing the indices of the boxes.
Output
For each query, output a line which contains an integer representing the total number of boxes.
Sample Input 1 | Sample Output 1 |
---|---|
5 0 1 1 2 2 5 1 1 2 4 5 2 3 4 3 2 3 4 1 2 |
5 2 2 4 3 |
题意:给出N个盒子,其中一些盒子可能会被放进另一些盒子里,Q个询问,每次询问给出M个盒子序号,求这M个盒子包含的盒子总数
题解:建树,然后从每个根节点搜出这个点的子树有多少点(包含自己)
因为m较小 所以我们可以暴力出任意两个点 一个点是否包含另一个点 如果包含 就把此点删去
寻找LCA可以用st表做 O(nlogn)预处理O(1)查询
但是题目中可能有多个根节点 我们可以建立一个虚拟点n+1 将所有的根都连向他 st表预处理做一次就可以了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int n,head[200005],tot,vis[200005],dpp[200005];
vector<int>root;
struct node{
int to,nex;
}edge[800005];
void add(int u,int v){
edge[tot].to=v;
edge[tot].nex=head[u];
head[u]=tot++;
}
int dfss(int t){
vis[t]=1;
for(int i=head[t];~i;i=edge[i].nex){
int v=edge[i].to;
if(!vis[v]){
dpp[t]+=dfss(v);
}
}
return dpp[t];
}
const int MAXN=200005;
int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列
struct ST
{
int mm[2*MAXN];
int dp[2*MAXN][20];//最小值对应的下标
void init(int n)
{
mm[0] = -1;
for(int i = 1;i <= n;i++)
{
mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1];
dp[i][0] = i;
}
for(int j = 1; j <= mm[n];j++)
for(int i = 1; i + (1<<j) - 1 <= n; i++)
dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
}
int query(int a,int b)//查询[a,b]之间最小值的下标
{
if(a > b)swap(a,b);
int k = mm[b-a+1];
return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
}
};
int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始
int P[MAXN];//P[i]表示点i在F中第一次出现的位置
int cnt;
ST st;
void dfs(int u,int pre,int dep)
{
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u];i != -1;i = edge[i].nex)
{
int v = edge[i].to;
if(v == pre)continue;
dfs(v,u,dep+1);
F[++cnt] = u;
rmq[cnt] = dep;
}
}
void LCA_init(int root,int node_num)//查询LCA前的初始化
{
cnt = 0;
dfs(root,root,0);
st.init(2*node_num-1);
}
int query_lca(int u,int v)//查询u,v的lca编号
{
return F[st.query(P[u],P[v])];
}
int ts[25],vs[25];
int main(){
int i,j;
scanf("%d",&n);
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
scanf("%d",&j);
if(!j){
add(n+1,i);
add(i,n+1);
root.push_back(i);
}
else{
add(i,j);
add(j,i);
}
dpp[i]++;
}
vis[n+1]=1;
for(i=0;i<root.size();i++){
int ds=root[i];
dfss(ds);
}
LCA_init(n+1,n+1);
int kk;
scanf("%d",&kk);
while(kk--){
int dt;
scanf("%d",&dt);
for(i=1;i<=dt;i++){
scanf("%d",&ts[i]);
}
int oo=0;
memset(vs,0,sizeof(vs));
for(i=1;i<=dt;i++){
for(j=i+1;j<=dt;j++){
int ros=query_lca(ts[i],ts[j]);
if(ros==ts[i])vs[j]=1;
else if(ros==ts[j]){
vs[i]=1;
break;
}
}
if(!vs[i])oo+=dpp[ts[i]];
}
printf("%d\n",oo);
}
return 0;
}