HDU 5923

地址传送门
题意:分别给你一个有根树还有一个图,有根树得每个节点代表图的一条边。每次询问给你一个集合,把集合里所有的点以及所有点的祖先节点代表得边连起来。问连接后的图中有多少个连通分量
思路:集合那不用说并查集了,这道题主要考虑如何只把他和他的祖父节点连接起来,于是把数组开成二维,dfs整棵树,每一节点建一个并查集数组,由于这道题是要把他的祖父节点也在集合,于是他祖父节点在一个集合的数他也会在一个集合,由此直接复制他父节点的并查集数组,再把自己节点的点放到一个集合中

#include<bits/stdc++.h>
using namespace std;
#define rd(a)  scanf("%d",&a)
int ss[10009][600];
int find(int x,int m)
{
    return x==ss[m][x]?x:ss[m][x]=find(ss[m][x],m);
}
struct node
{
    int u,v;
}ar[10009];
struct tre
{
    int v,next;

}a[10009];
int head[10009];
int o=0;
int n,m;
void intt()
{
        memset(head,-1,sizeof(head));
        o=0;
        for(int i=0;i<=m;i++)
        for(int j=0;j<=n;j++)
        ss[i][j]=j;

}
inline void add(int u,int v)
{
    a[o].v=v;
    a[o].next=head[u];
    head[u]=o++;

}
void dfs(int u)
{   
    for(int i=head[u];~i;i=a[i].next)
    {
        int v=a[i].v;
        for(int j=0;j<=n;j++)
        {
            ss[v][j]=ss[u][j];
        }
        int x=find(ar[v].u,v);
        int y=find(ar[v].v,v);
        if(x!=y)
        {
            ss[v][x]=y;
        }
        dfs(v);
    }
}
int main()
{
//  freopen("E://in.txt","r",stdin);
    int t;

    rd(t);

//  cout<<t;
    int tt=1;
    while(t--)
    {
            printf("Case #%d:\n",tt++);
        rd(n),rd(m);
        intt();
        for(int i=2;i<=m;i++)
        {
            int k;
            rd(k);
            add(k,i);
        }
        for(int i=1;i<=m;i++)
        {

            rd(ar[i].u),rd(ar[i].v);

        }
        add(0,1);
        dfs(0);
        int tt;
        rd(tt);
        while(tt--)
        {
            int nn;
            rd(nn);
            //for(int i=0;i<=n;i++)
            //ss[m+1][i]=i;
            int su[10009];
            for(int i=0;i<nn;i++) rd(su[i]);
            for(int i=0;i<=n;i++) ss[m+1][i]=ss[su[0]][i];
            for(int i=1;i<nn;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    int r=find(j,su[i]);
                    int x=find(r,m+1);
                    int y=find(j,m+1);
                    if(x!=y)
                    ss[m+1][x]=y;

                }

            }
            int ans=0;
            int vis[600];
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=n;i++)
            {   int x=find(i,m+1);
                if(!vis[x])
                {
                    vis[x]=1;
                    ans++;
                }
            }
            printf("%d\n",ans);

        }


    }



    return 0;

}

猜你喜欢

转载自blog.csdn.net/qq_37493070/article/details/79008633
hdu