DTOJ 2498:大步小步(babystep)

DTOJ 2498:大步小步(babystep)

【题目描述】
    从前有一个Baby从前还有一个网格图。Baby喜欢爆炸。Baby偶尔会炸掉网格图中的一条边(u,v)。之后他会尝试从u走到v如果他成功地从u走到v,他会很高兴;否则他会找人打架。从第二次爆炸开始,根据Baby此时心情的不同,Baby会炸掉不同的边。你被要求编写一个程序,对于每次爆炸,给出此时Baby是否还能从uv
【输入】
      第一行,一个整数R,代表网格图是R*R的。
     第二行,一个整数N,代表操作数。
     第三行,四个整数x1,y1,x2,y2,描述了第一次爆炸的边。
     以下N-1行,每行四个整数x1,y1,x2,y2,x1,y1,x2,y2’,分别描述Baby高兴时炸的边和想找人打架时炸的边。
【输出】
      输出N行,如果本次爆炸后Baby高兴,输出一行“HAHA”,否则输出一行“DAJIA”。
【样例输入】
2
2
1 1 1 2
1 1 2 1 1 2 2 2
【样例输出】
HAHA
DAJIA
【分析】
    这题因为有要用到上一轮的答案,所以离线几乎不可做,想想在线怎么做, 试着把删掉的边做并查集。不难发现,如果两条边有公共点,并且拐角为90度的两条边可以放在一个集合内,(用excel表格画画即可发现), 如果当前的线是横着的,那么判断一下其中一个端点的上下两条边是不是在一个集合中;如果当前的线是竖着的,那么判断一下其中一个端点的左右两条边是不是在一个集合中即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=500*500*2;
int rt[maxn],r,n,xa1,ya1,xb1,yb1,xa2,ya2,xb2,yb2;
inline int find ( int x ) { return x==rt[x] ? x : rt[x]=find(rt[x]); }
inline bool check ( int x,int y ) { return find(x)==find(y); }
inline void merge ( int x,int y ) { rt[find(y)]=find(x); }
inline int gp ( int x,int y ) { return (x-1)*r+y; }
inline bool pd ( int xa,int ya,int xb,int yb )
{
    if ( xa>xb || ya>yb ) swap(xa,xb),swap(ya,yb);
    bool flag=false;int t1,t2;
    if ( xa!=xb )
        if ( ya==1 ) t1=0,t2=gp(xa,ya);
        else if ( ya==r ) t1=0,t2=gp(xa,ya-1);
        else t1=gp(xa,ya-1),t2=gp(xa,ya);
    else
        if ( xa==1 ) t1=0,t2=gp(xa,ya);
        else if ( xa==r ) t1=0,t2=gp(xa-1,ya);
        else t1=gp(xa-1,ya),t2=gp(xa,ya);
    bool f=check(t1,t2);merge(t1,t2);
    return f;
}
int main()
{
    scanf("%d%d%d%d%d%d",&r,&n,&xa1,&ya1,&xb1,&yb1);
    for ( int i=1;i<=r*r;i++ ) rt[i]=i;puts("HAHA");
    bool f=pd(xa1,ya1,xb1,yb1);n--;
    while ( n-- )
    {
        scanf("%d%d%d%d%d%d%d%d",&xa1,&ya1,&xb1,&yb1,&xa2,&ya2,&xb2,&yb2);
        f=f?pd(xa2,ya2,xb2,yb2):pd(xa1,ya1,xb1,yb1);puts(f?"DAJIA":"HAHA");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dtoi_rsy/article/details/80951041
今日推荐