zoukankan      html  css  js  c++  java
  • 广告位招租 C-City

    题目描述

           如果城市A和城市B互通,城市B和城市C互通,那么城市A和城市C也互通,A、B、C三个城市算一个聚集点。先已知有n个城市和m条道路,想求的是有几个聚集点?但小S觉得太简单了,由于战争原因,某些城市会被导弹销毁掉,与之相应的道路也变得不可用。之前已经被销毁的不会被复原。现给定每次销毁的城市顺序,求每次销毁后聚集点有多少个。

    输入

    第一行输入n和m,表示城市数量和道路数量(1≤n≤104,1≤m≤2n)(1≤n≤104,1≤m≤2n)

    接下来m行,每行输入两个数ai和bi(1≤ai,bi≤n)(1≤ai,bi≤n)。表示ai和bi直接有道路

    第m+2行输入q,表示有q个城市会被销毁 (1≤q≤n)(1≤q≤n)

    接下来输入q个数,每行输入一个不重复的数,表示被销毁的城市

    输出

    输出一行q个数,每i个数表示第i个城市销毁后聚集点的数量

    样例输入

    8 9
    1 2
    1 3
    1 6
    2 4
    3 6
    4 5
    4 7
    5 7
    5 8
    4
    3 2 5 4
    

    样例输出

    1 2 3 3

    并查集,通过储存节点反向建树,之后再一个个加点寻找集合个数

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int maxn=1e4+10;
    
    struct node{
    	int a,b;
    	bool flag;//已经加过的点无须再加,通过flag进行标记
    }node[maxn<<1];
    
    int pre[maxn<<1];
    int n,m,t;
    vector<int> res;//储存需要删除的节点
    stack<int> st;//储存集合个数
    bool vis[maxn<<1];
    
    int find(int x)
    {
    	return pre[x]=(pre[x]==x?x:find(pre[x]));//状态压缩
    }
    
    void unite(int x,int y)
    {
    	x=find(x),y=find(y);
    	if(x>y)	pre[x]=y;//秩低向秩高的合并,防止树的退化
    	else pre[y]=x;
    }
    
    int main()
    {
    	ios::sync_with_stdio(false);
    	memset(vis,0,sizeof(vis));
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)
    		pre[i]=i;
    	for(int i=0;i<m;i++)
    		{
    			cin>>node[i].a>>node[i].b;
    			node[i].flag=false;
    		}
    	cin>>t;
    	for(int i=0;i<t;i++)
    		{
    			int tmp;
    			cin>>tmp;
    			vis[tmp]=true;//标记已经被删除的点
    			res.push_back(tmp);
    		}
    	vector<int>::iterator it;
    	/*it=res.end()-1;
    	for(int i=0;i<m;i++)
    		{
    			if(!vis[node[i].a]&&!vis[node[i].b]&&!node[i].flag)
    				{
    					unite(node[i].a,node[i].b);
    					node[i].flag=true;
    					cout<<i<<endl;
    				}
    		}*/
    	while(t--)
    		{
    			it=res.end()-1;
    			for(int i=0;i<m;i++)
    				{
    					if(!vis[node[i].a]&&!vis[node[i].b]&&!node[i].flag)
    						{
    							unite(node[i].a,node[i].b);
    							node[i].flag=true;
    						}
    				}
    			int sum=0;
    			for(int i=1;i<=n;i++)
    				if(find(i)==i)	sum++;
    			st.push(sum);
    			vis[*it]=false;//加点
    			res.erase(it);
    		}
    	int cnt=1;
    	while(!st.empty())
    		{
    			cout<<st.top()-cnt++<<' ';
    			st.pop();
    		}
    	cout<<endl;
    	return 0;
    }

    应有更快的解法

  • 相关阅读:
    必须掌握的八个DOS命令
    实况足球8 功略简解
    开始→运行→命令集锦
    必须掌握的八个DOS命令
    对称加密算法之DES算法
    让你的Linux像黑客帝国的画面一样炫酷
    古典密码之凯撒密码and换位密码
    用eclipse写jsp报以下错误
    mysql安装后,过一段时间,在命令行无法启动
    sql 日期函数
  • 原文地址:https://www.cnblogs.com/BlueDoor1999/p/13301383.html
Copyright © 2011-2022 走看看