HDU-5923 Prediction

There is a graph G=⟨VG,EG⟩ with |VG|=n and |EG|=m, and a magic tree T=⟨VT,ET⟩) rooted at 1, which contains m vertices.

Each vertex of the magic tree corresponds to an edge in the original graph G and each edge occurs in the magic tree exactly once.

Each query includes a set S(S⊆VT), and you should tell Mr. Frog the number of components in the modified graph G‘=(VG,E‘G), where E‘G is a set of edges in which every edge corresponds to a vertex v in magic tree T satisfying at least one of the following two conditions:

∙v∈S.
∙v is an ancestor of some vertices in S.

Note that the queries are independent, and namely one query will not influence another.
Input
The input contains several test cases and the first line of the input data is an integer T, denoting the number of test cases.

For each test case, the first line contains two integers n and m(1≤n≤500,1≤m≤10000), where n is the number of vertices and m is the number of edges.

The second line contains m - 1 integers describing the magic tree, i-th integer represents the parent of the (i + 1)-th vertex.

Then the following m lines describe the edges of the graph G. Each line contains two integers u and v indicating the two ends of the edge.

The next line contains only one integer q(1≤q≤50000), indicating the number of queries.

Then the following q lines represent queries, i-th line represents the i-th query, which contains an integer ki followed by ki integers representing the set Si.

It is guarenteed that ∑qi=1ki≤300000.
Output
For each case, print a line “Case #x:”, where x is the case number (starting from 1).

For each query, output a single line containing only one integer representing the answer, namely the number of components.

题意:其实就是给图和给树,然后树上的点是原图的边,现在就给你Q次询问给点一些点,
然后新形成的set包含这些点以及这些点的祖先,新图包含原图所有点和set内点代表
的边,现在问你新图的连通性如何。
分析:分析一下可以先O(n*m)暴力预处理一下到树上每个点的时候整个图联通性如何,
然后对于Q次询问我们就可以很方便的对给定的m个数进行暴力合并来求连通性就好了。
训练赛的时候头铁用set去搞直接MLE,赛后分析了一下发现并查集搞搞就好了,对于这
些联通性问题还是可以多想想并查集和dfs求环等O(n)时间和空间的数据结构。

#include <bits/stdc++.h>
using namespace std;
#define fuck(x) cout<<x<<endl
#define fuck1(x,y) cout<<x<<" "<<y<<endl
typedef long long LL;
const int maxn = 1e4+100;
const LL INF = 0x3f3f3f3f;
int n,R,C,m,fa[maxn];
vector<int> bc[maxn];
int cx[300000+100];
int Fa[maxn][505];
struct node{
       int u,v;
}Edge[maxn];
int Find(int id,int x){
    int r = x;
    while(Fa[id][r]!=r)r = Fa[id][r];
    while(x!=Fa[id][x]){
        int temp =Fa[id][x];
        Fa[id][x] = r;
        x = temp;
    }
    return r;
}
void dfs(int u,int fa){
    int k1 = Edge[u].u,k2 = Edge[u].v;
    int fx = Find(u,k1),fy = Find(u,k2);
    Fa[u][fy] = fx;
    for(auto e:bc[u]){
        if(e==fa)continue;
        for(int i = 1;i<=n;i++)Fa[e][i] = Fa[u][i];
        dfs(e,u);
    }
}
int main()
{
    int T,N;
    scanf("%d",&T);
    int Case = 0;
    while(T--){
         printf("Case #%d:\n",++Case);
         scanf("%d%d",&n,&m);
         for(int i = 1;i<=m;i++)bc[i].clear();
         for(int i = 1;i<=m;i++)for(int j = 1;j<=n;j++)Fa[i][j] = j;
         for(int i = 2;i<=m;i++){
            int v;
            scanf("%d",&v);
            fa[i] = v;
            bc[v].push_back(i);
         }
         for(int i = 1 ;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            Edge[i].u = u,Edge[i].v = v;
         }
         dfs(1,0);
         int q;
         scanf("%d",&q);
         while(q--){
            int num;
            scanf("%d",&num);
            for(int i =1;i<=num;i++)scanf("%d",&cx[i]);
            for(int i = 1;i<=n;i++)Fa[0][i] = Fa[cx[1]][i];
            for(int i = 2;i<=num;i++){
                for(int j = 1;j<=n;j++){
                    int fx  = Find(0,j),fy = Find(cx[i],j);
                    fy = Find(0,fy);
                    Fa[0][fy] = fx;
                   // fuck1(fx,fy);
                }
            }
            int ans = 0;
            //fuck(Find(0,1));
            for(int i = 1;i<=n;i++)if(Find(0,i)==i)ans++;
            printf("%d\n",ans);
         }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值