[AMPPZ 2013]Bytehattan
题目大意:有一个网格图,每次可以炸掉炸掉网格图中的一条边(u, v)。之后他会尝试从u走到v。
如果他成功地从u走到v,他会很高兴;否则他会找人打架。
从第二次爆炸开始,根据此时心情的不同,会炸掉不同的边。
注意此题是强制在线!!!!
对于这种题目,裸的并查集显然是不对的(虽然可以对50分,部分分),但显然不是最优的,听完题解以后,它是一种变相的并查集。
我们维护定义并查集的每一个节点就是网格图中的
每一个方格和最外面的“世界”。一开始他们互不相连,每次如果某条边断了,那么就会有两个方格或方格和世界相连,那么我们就将这两样东西连在一起,如果我们发现出现了一个环(及没连接之前就已经在一个联通块中),那么就是不能从u走到v,因为这一块已经与世隔绝了,所以不可能再想通,否则即为可以走到。
此题思想极好.(因为某位会miao的人http://www.cnblogs.com/dyllalala/p/3903311.html觉得图画的太丑,就不上图了,因为他画的特别好)
#include<iostream>
#include<cstdio>
using namespace std;
int R;
int father[500*600];
int n;
int now;
int getId(int x, int y)
{
if ((x == 0) || (x == R)) return 0;
if ((y == 0) || (y ==R)) return 0;
return (x - 1) * (R - 1) + y;
}
int find(int x)
{
if(father[x]==x)return x;
return father[x]=find(father[x]);
}
void UNION(int x,int y)
{
father[find(x)]=find(y);
}
void did(int x1,int y1,int x2,int y2)
{
if(x1>x2)swap(x1,x2);
if(y1>y2)swap(y1,y2);
int x,y;
if(x1==x2)
{
x=getId(x1- 1,y1);
y=getId(x1, y1);
}
else
{
x=getId(x1, y1- 1);
y=getId(x1, y1);
}
if(find(x)==find(y))
{
now=1;
puts("DAJIA");
}
else
{
now=0;
puts("HAHA");
UNION(x,y);
}
return ;
}
int main()
{
scanf("%d",&R);
scanf("%d",&n);
for(int i=1;i<=R*R;i++)
father[i]=i;
int x1,x2,y1,y2,x3,y3,x4,y4;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
for(int i=1;i<=n;i++)
{
if(now==0)
{
did(x1,y1,x2,y2);
}
else
{
did(x3,y3,x4,y4);
}
if(i!=n)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
scanf("%d%d%d%d",&x3,&y3,&x4,&y4);
}
}
return 0;
}