【输入格式】
第一行一个正整数 n。
接下来 n行描述集合 A1,A2,...,An。第一个数表示集合中元素的个数,之后给出集合中的元素。
接下来一行包含一个正整数 q。
接下来 q行每行描述一个询问,格式与之前相同。
【输出格式】
对于每组询问,输出一个整数表示答案。
【样例输入】
7
0
1 1
1 1
1 2
2 2 3
0
2 2 6
3
2 2 3
2 3 5
2 4 5
【样例输出】
3
3
4
【数据规模及约定】
对于 20%的数据,n,q<=50
对于 40%的数据,n,q<=1000
对于 100%的数据,n,q<=200000
输入文件大小不超过 15MB。
题解:题目中集合与集合的关系可以抽象成树的结构。
定义一个新集合就相当于是在一堆点的lca上在加入一个新节点
查询就是求一些点到根的路径上一共覆盖了多少点,可以利用dfs序以及点与点之间lca的深度关系来计算。
按dfs序排序,这样每个点都与与他距离最近的点相连,计算对答案的贡献的时候只需要+deep[now]-deep[lca(now,now-1)] 即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 10000003
#define M 500000
using namespace std;
int a[N],b[N],f[20][M],mi[20];
int point[M],next[M],v[M],pos[M],w[M],tot,cnt,size;
int n,m,t,l[N],deep[N],q[M],cur[M],st[M];
void add(int x,int y,int k)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; w[tot]=k;
//cout<<x<<" "<<y<<" "<<k<<endl;
}
void change(int x,int y)
{
deep[y]=deep[x]+1;
f[0][y]=x;
for (int i=1;i<=18;i++)
{
if (deep[y]-mi[i]<0) break;
f[i][y]=f[i-1][f[i-1][y]];
}
}
int lca(int x,int y)
{
if (deep[x]<deep[y]) swap(x,y);
int k=deep[x]-deep[y];
for (int i=0;i<=18;i++)
if ((k>>i)&1)
x=f[i][x];
if (x==y) return y;
for (int i=18;i>=0;i--)
if (f[i][x]!=f[i][y])
{
x=f[i][x];
y=f[i][y];
}
return f[0][x];
}
void dfs(int x)
{
q[x]=++size;
for (int i=point[x];i;i=next[i])
dfs(v[i]);
}
void dfs1()
{
int top=0;
for (int i=0;i<=n;i++) cur[i]=point[i];
st[++top]=0;
while(top)
{
int x=st[top];
if (!cur[x])
{
--top;
q[x]=++size;
continue;
}
int vt=v[cur[x]];
st[++top]=vt; cur[x]=next[cur[x]];
}
}
int cmp(int x,int y)
{
return q[x]<q[y];
}
int main()
{
freopen("set.in","r",stdin);
freopen("set.out","w",stdout);
scanf("%d",&n);
mi[0]=1;
for (int i=1;i<=19;i++) mi[i]=mi[i-1]*2;
for (int i=1;i<=n;i++)
{
int x; scanf("%d",&x); l[i]=l[i-1]+x;
for (int j=l[i-1]+1;j<=l[i];j++)
scanf("%d",&a[j]);
}
for (int i=1;i<=n;i++)
{
if (l[i-1]-l[i]==0)
{
pos[i]=++cnt;
add(0,cnt,i);
change(0,cnt);
continue;
}
if (l[i]-l[i-1]==1)
{
pos[i]=++cnt;
add(pos[a[l[i]]],cnt,i);
change(pos[a[l[i]]],cnt);
continue;
}
int t=lca(pos[a[l[i-1]+1]],pos[a[l[i-1]+2]]);
for (int j=l[i-1]+3;j<=l[i];j++)
t=lca(pos[a[j]],t);
pos[i]=++cnt;
add(t,cnt,i);
change(t,cnt);
}
//dfs(0);
dfs1();
//for (int i=1;i<=n;i++)
//cout<<q[i]<<" ";
//cout<<endl;
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int x; scanf("%d",&x);
for (int j=1;j<=x;j++)
scanf("%d",&b[j]);
sort(b+1,b+x+1,cmp);
//for (int j=1;j<=x;j++)
// cout<<b[j]<<" ";
//cout<<endl;
int ans=0;
ans+=deep[b[1]];
for (int j=2;j<=x;j++)
ans+=deep[b[j]]-deep[lca(b[j],b[j-1])];
printf("%d\n",ans);
}
}