HDU5923——Prediction(数据结构,并查集)

46 篇文章 1 订阅
9 篇文章 0 订阅

Prediction

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 476    Accepted Submission(s): 109


Problem Description
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(SVT) , and you should tell Mr. Frog the number of components in the modified graph  G=(VG,EG) , where  EG  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:

vS .
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( 1n500,1m10000 ), 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( 1q50000 ), 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=1ki300000 .
 

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.
 

Sample Input
  
  
1 5 4 1 1 3 1 2 2 3 3 4 4 5 3 1 2 2 2 3 2 2 4
 

Sample Output
  
  
Case #1: 3 2 1
Hint
magic tree and the original graph in the sample are: In the first query, S = {2} and the modified graph G' = {{1, 2, 3, 4}, {(1, 2), (2, 3)}}, thus the number of the components in the modified graph is 3. In the second query, S = {1, 2, 3}, where 1 is the ancestor of 2 (and 3) in the magic tree, and the modified graph G'' = {{1, 2, 3,4}, {(1, 2), (2, 3), (3, 4)}}, therefore the number of the components in the modified graph is 2. In the third query, S = {1, 2, 3, 4}, where 1 is the ancestor of 2 (and 4), 3 is the ancestor of 4, and the modified graph G' = {{1, 2, 3,4}, {(1, 2), (2, 3), (3,4), (4, 5)}}, therefore the answer equals to 1.


题意:分别给你一个有根树还有一个图,有根树得每个节点代表图的一条边。每次询问给你一个集合,把集合里所有的点以及所有点的祖先节点代表得边连起来。问连接后的图中有多少个连通分量

思路:很容易发现,用DFS遍历一棵树的时候。是从祖先遍历到儿子的。那么可以建立m个并查集,在遍历的时候预处理出每一个节点及其祖先节点的并查集。然后查询的时候只需要把这些并查集合并即可。



#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <ctime>
#include <cstdlib>
#include <iostream>
#define pi 3.1415926
#define mod 1000000007
#define MAXM 10010
#define MAXN 510
#define INF 0x3f3f3f3f3f3f3fLL
using namespace std;

struct edge{
	int v,next;
}e[MAXM];
int head[MAXM];
int tot=0;

void add(int u,int v){
	e[tot].v=v;
	e[tot].next=head[u];
	head[u]=tot++;
}

struct node{
	int u,v;
};

std::vector<node> G;

int f[MAXM][MAXN];
void init(int m,int n){
	for(int i=0;i<=m;i++){
		for(int j=0;j<=n;j++){
			f[i][j]=j;
		}
	}
}
int find(int m,int x){
	if(f[m][x]==x)
		return x;
	else
		return f[m][x]=find(m,f[m][x]);
}
void unite(int m,int x,int y){
	x=find(m,x);
	y=find(m,y);
	if(x==y)
		return;
	else
		f[m][y]=x;
}

void dfs(int x){
  	for(int k=head[x];k!=-1;k=e[k].next){
 		int v=e[k].v;
		memcpy(f[v],f[x],sizeof(f[v]));
		unite(v,G[v-1].u,G[v-1].v);
		//if(x!=0)
          //  unite(v,G[x-1].u,G[v-1].u);
		dfs(v);
	}
}

int res[MAXM];
int vis[MAXN];
int main()
{
	int t;
	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++){
		printf("Case #%d:\n",cas);
		int n,m;
		scanf("%d%d",&n,&m);
		init(m,n);
		tot=0;
		G.clear();
		memset(head,-1,sizeof(head));
		add(0,1);
		for(int i=2;i<=m;i++){
			int x;
			scanf("%d",&x);
			add(x,i);
		}
		for(int i=0;i<m;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			node temp;
			temp.u=u,temp.v=v;
			G.push_back(temp);
		}
		dfs(0);
		int q;
		scanf("%d",&q);
		while(q--){
			int cnt;
			memset(vis,0,sizeof(vis));
			scanf("%d",&cnt);
			for(int i=0;i<=n;i++){
				f[m+1][i]=i;
			}
			for(int i=0;i<cnt;i++){
				scanf("%d",&res[i]);
			}
			memcpy(f[m+1],f[res[0]],sizeof(f[m+1]));
			for(int i=1;i<cnt;i++){
                for(int j=1;j<=n;j++){
				int r=find(res[i],j);
				unite(m+1,r,j);
				}
				//unite(m+1,G[res[0]-1].u,G[res[i]-1].u);
			}
			int ans=0;
			for(int i=1;i<=n;i++){
 				int temp=find(m+1,i);
				//cout<<temp<<endl;
				if(!vis[temp]){
                    	vis[temp]=1;
				ans++;
				}
			}
			printf("%d\n",ans);
		}
	}
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值