【JZOJ 3839】Baby Step

Description

从前有一个Baby。
从前还有一个网格图。
Baby 喜欢爆炸。
Baby 偶尔会炸掉网格图中的一条边(u, v)。之后他会尝试从u 走到v。
如果他成功地从u 走到v,他会很高兴;否则他会找人打架。
从第二次爆炸开始,根据Baby 此时心情的不同,Baby 会炸掉不同的边。
你被要求编写一个程序,对于每次爆炸,给出此时Baby 是否还能从u 到v。

Solution

这题因为有要用到上一轮的答案,所以离线几乎不可做,想想在线怎么做,
试着把删掉的边做并查集,
发现,如果两条边有公共点,并且拐角为90度的两条边可以放在一个集合内,(读者自己用excel表格画画即可发现),
如果当前的线是横着的,那么判断一下其中一个端点的上下两条边是不是在一个集合中,
如果当前的线是竖着的,那么判断一下其中一个端点的左右两条边是不是在一个集合中,

复杂度: O(m)

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=800;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int a[N];
bool z[N][N][2];
int g[N*N*2+N];
int fx1[6][3]={{-1,0,1},{-1,1,1},{-1,0,0},{0,0,1},{0,1,1},{1,0,0}};
int fx2[6][3]={{0,0,1},{1,0,1},{0,1,0},{0,-1,1},{0,-1,0},{1,-1,1}};
void H(int &q,int &w,int &e,int x,int y,int x1,int y1)
{
    if(x1<x||y1<y)swap(x,x1),swap(y,y1);
    e=(x!=x1);q=x,w=y;
}
int H(int q,int w,int e)
{
    if(!q||!w||(e&&(w>n||q>=n))||(!e&&(q>n||w>=n)))return 0;
    return (q*n-n+w)*2-1+e;
}
int gf(int q)
{
    return g[q]=(g[q]!=q?gf(g[q]):q);
}
int main()
{
    int q,w,e,x,y,x1,y1,_;
    read(n),read(_);_--;
    fo(i,0,n*n*2+n)g[i]=i;
    fo(i,0,n+1)z[i][0][0]=z[i][0][1]=z[0][i][0]=z[0][i][1]=
    z[i][n][0]=z[n][i][1]=z[n+1][i][0]=z[n+1][i][1]=z[i][n+1][0]=z[i][n+1][1]=1;
    read(x),read(y),read(x1),read(y1);H(q,w,e,x,y,x1,y1);
    fo(i,0,5)if(z[q+fx2[i][0]][w+fx2[i][1]][e^fx2[i][2]])
        g[gf(H(q+fx2[i][0],w+fx2[i][1],e^fx2[i][2]))]=H(q,w,e);
    z[q][w][e]=1;printf("HAHA\n");ans=1;
    while(_--)
    {
        if(!ans)fo(i,1,4)read(q);
        read(x),read(y),read(x1),read(y1);
        H(q,w,e,x,y,x1,y1);
        if(ans)fo(i,1,4)read(x);    
        // if(z[q][w][e]){ans=0;printf("DAJIA\n");continue;}
        ans=1;
        if(!e)
        {
            int t=-1,t1=-1;
            fo(i,0,2)if(z[q+fx1[i][0]][w+fx1[i][1]][e^fx1[i][2]])
                t=gf(g[H(q+fx1[i][0],w+fx1[i][1],e^fx1[i][2])]);
            fo(i,3,5)if(z[q+fx1[i][0]][w+fx1[i][1]][e^fx1[i][2]])
                t1=gf(g[H(q+fx1[i][0],w+fx1[i][1],e^fx1[i][2])]);
            if(t==t1&&t1!=-1)ans=0;
            gf(H(q,w,e));
            fo(i,0,5)
            if(z[q+fx1[i][0]][w+fx1[i][1]][e^fx1[i][2]])
                g[gf(H(q+fx1[i][0],w+fx1[i][1],e^fx1[i][2]))]=gf(H(q,w,e));
        }else 
        {
            int t=-1,t1=-1;
            fo(i,0,2)if(z[q+fx2[i][0]][w+fx2[i][1]][e^fx2[i][2]])
                t=gf(g[H(q+fx2[i][0],w+fx2[i][1],e^fx2[i][2])]);
            fo(i,3,5)if(z[q+fx2[i][0]][w+fx2[i][1]][e^fx2[i][2]])
                t1=gf(g[H(q+fx2[i][0],w+fx2[i][1],e^fx2[i][2])]);
            if(t==t1&&t1!=-1)ans=0;
            fo(i,0,5)if(z[q+fx2[i][0]][w+fx2[i][1]][e^fx2[i][2]])
                g[gf(H(q+fx2[i][0],w+fx2[i][1],e^fx2[i][2]))]=gf(H(q,w,e));
        }
        z[q][w][e]=1;
        if(ans)printf("HAHA\n");else printf("DAJIA\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值