bzoj 5048: 塌陷的牧场

题解:

看完题解感觉好水,自己智障
将障碍反向运动,删掉扫过的点。
每个点维护四个方向的并查集,优化暴力就可以了。
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
struct node{
    int x,y;
}a[10010];
int fa[5][2010][2010];
int n,m,e,q,ans,k;
bool del[2010][2010];
char ch[10];
void erase(int x,int y)
{
    if(del[x][y]) return;
    del[x][y]=true;
    fa[0][x][y]--;
    fa[1][x][y]++;
    fa[2][x][y]--;
    fa[3][x][y]++;
    ans++;
}
int find01(int o,int x,int y)
{
    if(fa[o][x][y]!=x) fa[o][x][y]=find01(o,fa[o][x][y],y);
    return fa[o][x][y];
}
int find23(int o,int x,int y)
{
    if(fa[o][x][y]!=y) fa[o][x][y]=find23(o,x,fa[o][x][y]);
    return fa[o][x][y];
}
void up(int k)
{
    for(int i=1;i<=e;i++)
    {
        int x=a[i].x,y=a[i].y;
        a[i].x-=k;
        if(y<1||y>m) continue;
        if(x<1) continue;
        if(x>n) x=n;
        while(true)
        {
            x=find01(0,x,y);
            if(x<1||x<a[i].x) break;
            erase(x,y);
        }
    }
}
void down(int k)
{
    for(int i=1;i<=e;i++)
    {
        int x=a[i].x,y=a[i].y;
        a[i].x+=k;
        if(y<1||y>m) continue;
        if(x>n) continue;
        if(x<1) x=1;
        while(true)
        {
            x=find01(1,x,y);
            if(x>n||x>a[i].x) break;
            erase(x,y);
        }
    }
}
void left(int k)
{
    for(int i=1;i<=e;i++)
    {
        int x=a[i].x,y=a[i].y;
        a[i].y-=k;
        if(x<1||x>n) continue;
        if(y<1) continue;
        if(y>m) y=m;
        while(true)
        {
            y=find23(2,x,y);
            if(y<1||y<a[i].y) break;
            erase(x,y);
        }
    }
}
void right(int k)
{
    for(int i=1;i<=e;i++)
    {
        int x=a[i].x,y=a[i].y;
        a[i].y+=k;
        if(x<1||x>n) continue;
        if(y>m) continue;
        if(y<1) y=1;
        while(true)
        {
            y=find23(3,x,y);
            if(y>m||y>a[i].y) break;
            erase(x,y);
        }
    }
}
int main()
{
    scanf("%d %d %d %d",&n,&m,&e,&q);
    memset(del,false,sizeof(del));
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++)
            fa[0][i][j]=fa[1][i][j]=i,fa[2][i][j]=fa[3][i][j]=j;
    for(int i=1;i<=e;i++) scanf("%d %d",&a[i].x,&a[i].y),erase(a[i].x,a[i].y);
    for(int i=1;i<=n;i++) a[++e].x=i,a[e].y=0,a[++e].x=i,a[e].y=m+1;
    for(int i=1;i<=m;i++) a[++e].x=0,a[e].y=i,a[++e].x=n+1,a[e].y=i;
    while(q--)
    {
        scanf("%s %d",ch+1,&k);
        ans=0;
        if(ch[1]=='U') down(k);
        if(ch[1]=='D') up(k);
        if(ch[1]=='L') right(k);
        if(ch[1]=='R') left(k);
        printf("%d\n",ans);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值