nbut 1058 火烧赤壁 2
来源:互联网 发布:java 调用ant 编辑:程序博客网 时间:2024/06/09 20:02
转载至http://blog.csdn.net/a1dark
题目表面是删点并查集,但其实不存在真正意义上的此类代码(至少笔者目前没见过Orz)
实际上是添点并查集的逆序操作,此文转载某大牛的博客,并使用了邻接链表大量减少空间。
整个代码除了添点并查集的逆序操作这个精华之外还有关于并查集部分的路径压缩(否则铁定的tle)
读者可自行编写并查集部分。欢迎尝试。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=200005; //题目要求数据
int mpt[maxn]; //用于并查集
int num[maxn]; //用于离线记录数据
int ans[maxn]; //用于保存答案
int vis[maxn]; //用于标记是否在集合中
int n,m,temp; //N个点、M条边、temp表示答案的变量
struct node{
int to,next;//用于临界表存储
}map[maxn*2];
int head[maxn];
int k;//临界表索引
void add(int x,int y)//邻接表添加边
{
k++;
map[k].to = y;
map[k].next = head[x];
head[x] = k; //邻接表编号
//printf("%d %d %d \n",map[k].to,map[k].next,head[x]);
}
void init()//初始化并查集
{
for(int i = 0;i < n; i++)
{
mpt[i] = i;
}
}
int find(int x)//寻找祖先并压缩路径
{
int r=x;
while(r!=mpt[r])
{
r=mpt[r];
}
int b=x;
int f;
while(b != r)//一条路径上面的点全部指向一个父节点
{
f=mpt[b];
mpt[b]=r;
b=f;
}
return r;
}
void merge(int x,int y)//合并两个点
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
mpt[fx]=fy;
temp--; //若祖先不同则合并后少一个连通块
}
}
int main()
{
while(scanf("%d%d",&n,&m) != EOF)
{
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
k=-1;//初始化邻接表
for(int i = 0;i < maxn; i++)
{
head[i] = -1;
}
int a,b;
for(int i=0;i < m;i++)
{
scanf("%d%d",&a,&b);
add(a,b);//加入邻接表
add(b,a);
}
int test;
scanf("%d",&test);//删除点的数量
for(int i = 0;i < n; i++)//初始化标记数组
{
vis[i] = 0;
}
for(int i = 1;i <= test; i++)
{
scanf("%d",&num[i]);
vis[num[i]] = 1; //标记
}
init();//初始化并查集
temp=n - test; //点全部删完后留下的点的数量
for(int i = 0;i < n; i++)
{
if(vis[i] == 0)
{
int now = i;
for(int j = head[now];j != -1 ;j = map[j].next) //重新构图
{
int s=map[j].to;
if(vis[s] == 0)
{
merge(now,s);
}
}
}
}
ans[test+1] = temp;//将答案逆序保存进ans数组中
temp++; //每一次多一个点则+1
for(int i = test;i >= 1; i--)//循环test次
{
int now = num[i];
vis[now] = 0;
for(int j = head[now];j != -1;j = map[j].next)//找相邻的边
{
int s = map[j].to;
if(vis[s] == 0)//若相邻的边在图上、则合并
{
merge(now,s);
}
}
ans[i]=temp;//记录当前答案
temp++;
}
for(int i=1;i<=test+1;i++)//输出答案
{
printf("%d\n",ans[i]);
}
}
return 0;
}
- nbut 1058 火烧赤壁 2
- NBUT 1508 火烧赤壁2【离线+逆序并查集】
- NOJ[1508] 火烧赤壁2
- 火烧赤壁的故事
- 火烧赤壁 洛谷 vijos
- 洛谷p1496火烧赤壁
- 2774 火烧赤壁(排序贪心)
- NOJ——1508火烧赤壁2(并查集+启发式合并+逆序加边)
- 1165 火烧赤壁 vijosoj (数组模拟)
- vijos 1165_火烧赤壁_离散
- vijos p1103校门外的树 和 P1165火烧赤壁
- (NOIP2015)复赛模拟试题 vijos1165 火烧赤壁
- 赤壁
- NBUT
- NBUT
- NBUT
- NBUT
- NBUT
- [noj 1521] +-字符串
- 【转载】[hrbust 2029] 二十世纪八十年代(状态压缩)
- [noj1393] 哦妈咪妈咪吼
- NOJ [1060] Countless Core Computers
- [HDOJ 1556] Color the ball(线段树成段更新入门)
- nbut 1058 火烧赤壁 2
- 杨辉三角
- [nbut 1405] bridge and island
- [1411] TT要吃肉
- [NOJ 1137] The Running Man
- 如何自己构造ADO的ConnectionString
- 有关SIP中的PRACK的含义和使用
- 自然对数
- outStream.flush()