• [1508] 火烧赤壁2

  • 时间限制: 1000 ms 内存限制: 65535 K
  • 问题描述
  • 上次出了一道火烧赤壁的题目给当时的新生,也就是你们的上一届学长们做,那么这次,我又想到了另一个想法。
    上次的火烧赤壁的题号为1274
    这次稍微难一点,我们来个火烧赤壁2吧。

    Hungar个人很喜欢曹操这个人,所以这次有机会穿越到三国时代,他想帮助曹操打赢赤壁之战。
    但是他去晚了,当他穿越到那的时候发现大火已经在蔓延了,所以他能做的就是马上告诉曹操把已经着火的船的锁链(船与船相连都是靠锁链达到的)给破坏掉使火不会蔓延到附近的船只。

    现在告诉你曹操一共有N艘船,M条铁链,船只编号从0开始到n-1。
    然后再告诉你依次着火的船只编号,问舍弃那艘船以后,剩下的船只能形成几个连通块(只要是被铁链连在一起的全部船只,就算一共连通块)。
    船与船之间可能存在多条锁链。

  • 输入
  • 输入包括第一行两个整数,N(1 <= N <= 2M)和M(1 <= M <= 200,000)。
    接下来M行,每行包括两个整数x和y(x != y),分别表示编号为x和y的船只被一根锁链连起来。
    再接下来一个正整数T表示着火船只的数量。
    接下来T行,每行包含一个整数z表示被烧船只的编号,编号不会出现一样的,也就是说已经被烧的船只不会再去烧它。
  • 输出
  • 输出z+1个数,第一行为着火前这些船的连通块数,后z行表示每次依次烧掉一只船后,剩下的连通块数。
  • 样例输入
  • 8 13
    0 1
    1 6
    6 5
    5 0
    0 6
    1 2
    2 3
    3 4
    4 5
    7 1
    7 2
    7 6
    3 6
    5
    1
    6
    3
    5
    7
  • 样例输出
  • 1
    1
    1
    2
    3
    3

思路:题目中舍弃的船是有先后次序的,前面的会对后面的造成影响。然后什么是逆序加边?先把所有的连接点对和舍弃的船全存起来,然后把所有不在舍弃的点集合中的点进行合并,比如题目中一开始就只存在0,2,4这三个点,且没有边可以合并(任意边均有至少一个点属于被舍弃的集合)这样完成之后的连通情况记为F。然后可以推出:我最后一次舍弃的是7号,求此时的连通块的做法。求7号时显然前面的点已经全部被舍弃,那么这种情况等价于F;然后往前推求舍弃5的情况,显然此时情况等价于F加上7所在的所有边。然后3、6、1情况以此类推。由此可见逆序可以减小复杂度,不然我顺序每求一次都要把连通情况初始化为F,然后又进行倒序加边。复杂度由N范围决定,数据一大肯定超时。然后此题WA多次,最后几次是由于多输出了一个数,最后因为文字太多看不清用文件重定向才发现是多输出了一个数……

代码:

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define MM(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long LL;
const int N=200010;
int pre[2*N];
int ran[2*N];
int vis[2*N];
vector<int>E[N];
vector<int>pos;
inline int find(const int &a)
{
if(a!=pre[a])
return pre[a]=find(pre[a]);
return pre[a];
}
inline int joint(const int &a,const int &b)
{
int fa=find(a),fb=find(b);
if(fa!=fb)
{
if(ran[fa]>=ran[fb])
{
ran[fa]+=ran[fb];
pre[fb]=fa;
ran[fb]=0;
}
else
{
ran[fb]+=ran[fa];
pre[fa]=fb;
ran[fa]=0;
}
return 1;
}
return 0;
}
inline void init(int n)
{
for (int i=0; i<n; i++)
{
pre[i]=i;
ran[i]=1;
vis[i]=1;
E[i].clear();
}
pos.clear();
}
inline void init2(int n)
{
for (int i=0; i<n; i++)
{
pre[i]=i;
ran[i]=1;
}
}
int main(void)
{
int i,j,x,y,z,n,m,t,k;
while (~scanf("%d%d",&n,&m))
{
init(n);
for (i=0; i<m; i++)
{
scanf("%d%d",&x,&y);
E[x].push_back(y);
E[y].push_back(x);
joint(x,y);
}
k=0;
for (i=0; i<n; i++)
{
if(ran[i]>=1)
k++;
}
init2(n);
k=n;
scanf("%d",&t);
for (i=0; i<t; i++)
{
scanf("%d",&z);
pos.push_back(z);
if(vis[z]==1)
{
vis[z]=0;
k--;
}
}
vector<int>ans;
for (i=0; i<n; i++)
{
if(vis[i]==1)
{
for (j=0; j<E[i].size(); j++)
{
if(vis[E[i][j]])
{
if(joint(E[i][j],i))
k--;
}
}
}
}
ans.push_back(k);
int cnt=pos.size(),fa,fb;
for (i=cnt-1; i>=0; i--)
{
int v=pos[i];
vis[v]=1;
k++;
for (j=0; j<E[v].size(); j++)
{
if(vis[E[v][j]])
{
if(joint(E[v][j],v))
k--;
}
}
ans.push_back(k);
}
cnt=ans.size();
for (i=cnt-1; i>=0; i--)
printf("%d\n",ans[i]);
}
return 0;
}

最新文章

  1. 如果把带有html的标记的字符串从服务端传到页面上,需要对其进行编码。Ajax.JavaScriptStringEncode()
  2. os模块汇总
  3. 简要分析webpack打包后代码
  4. MySql学习(三) —— 子查询(where、from、exists) 及 连接查询(left join、right join、inner join、union join)
  5. CSS 高级技巧汇总
  6. 使用JUnit4进行java单元测试
  7. iOS:访问地址薄
  8. python(一)入门
  9. Python中几种数据类型list, tuple,dict,set的使用演示
  10. Trie树/字典树题目(2017今日头条笔试题:异或)
  11. python爬虫入门(三)XPATH和BeautifulSoup4
  12. 使用Visual Studio Team Services敏捷规划和项目组合管理(六)——VSTS仪表盘的使用
  13. 基于bootstrap-treeview做的一个漂亮的无限分类树层级联动菜单
  14. Python高级网络编程系列之第二篇
  15. CentOS下Redisserver安装配置
  16. C++标准转换运算符static_cast
  17. cassandra用户名和密码的设置
  18. Spring3 MVC请求参数获取的几种方法[转]
  19. Day24-26 项目练习(图书商城)
  20. 全面了解 Nginx 主要应用场景

热门文章

  1. Django 模板函数
  2. Java中的Static修饰符
  3. lua 分割字符串
  4. C# 使用Epplus导出Excel [5]:样式
  5. 前端应该如何去认识http
  6. pre-commit钩子,代码质量检查
  7. Python头脑风暴1
  8. HDU:4185-Oil Skimming
  9. MVC&amp;JQuery如何根据List动态生成表格
  10. 安装好的IIS,发布成功后打开网站出现错误