bzoj5048: 塌陷的牧场

Description

农夫小Q将他的奶牛们饲养在一个长n宽m的矩形网格牧场中。行从上到下依次编号为1到n,列从左往右依次编号为1
到m。为了防止奶牛们逃跑,小Q在牧场外圈安装了一排电网,只要奶牛走出这个n*m的矩形,就会触电死去。在牧
场中,有e个格子塌陷了,一旦奶牛踩在上面,就会掉下去摔死。小Q为了饲养尽可能多的奶牛,在每个没有塌陷的
格子上,都饲养着一头奶牛。tangjz偷走了小Q的口哨,并用口哨向奶牛们依次施放了q条指令,每条指令包含两个
参数d和k,d表示上下左右之一的方向,k表示前进步数。发出指令后,每头奶牛都会听话地执行指令,甚至会因此
丧生。所有奶牛移动完毕之后,tangjz才会施放下一条指令。请写一个程序统计每条指令中小Q损失了多少头奶牛
Input

第一行包含4个正整数n,m,e,q(1<=n,m,q<=2000,0<=e<=min(nm,2000))
分别表示牧场的长宽、塌陷的格子数以及指令数。
接下来e行,每行两个正整数x_i,y_i(1<=x_i<=n,1<=y_i<=m)
表示每个塌陷格子的坐标。输入数据保证每个格子不会被描述多次。
接下来q行,每行包含一个字符d和一个正整数k(1<=k<=2000)
描述每条指令。其中UDLR分别表示上下左右。
Output

输出q行,每行一个整数,即第i条指令中损失的奶牛数量。
Sample Input

3 5 3 4

1 4

2 2

3 3

R 2

L 1

D 2

U 1
Sample Output

10

0

2

0

前言

这场比赛一开始想的就是这题QAQ
从障碍开始倒着走应该是很简单的吧
然后不知道为什么我就把障碍先向左走然后向下走死掉的奶牛想成了下面黑色部分
这里写图片描述
然后明明只有黄色线的嘛QAQ然后做了半天没做出来

题解

看完题解感觉自己宛如智障。。

然后我们就对一个点向四个方向维护并查集就好了。。
维护的是这一个方向下一个没有没删的点是哪一个。。
然后每次就跳并查集

具体看代码
CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=2005;
int n,m,q,e;
struct qq
{
    int x,y;
}s[N*5];//障碍
int f[4][N][N];//往上的并查集   往下的并查集   往左的并查集   往右的并查集 
bool ok[N][N];
int ans=0;
int find01(int op,int x,int y){return f[op][x][y]==x?x:f[op][x][y]=find01(op,f[op][x][y],y);}
int find23(int op,int x,int y){return f[op][x][y]==y?y:f[op][x][y]=find23(op,x,f[op][x][y]);}
void Del (int x,int y)
{
    if (ok[x][y]==false) return ;
    ok[x][y]=true;
    f[0][x][y]--;f[1][x][y]++;
    f[2][x][y]--;f[3][x][y]++;
    ans++;
}
void up (int k)//所以的障碍上走k步
{
    for (int u=1;u<=e;u++)
    {
        int x=s[u].x,y=s[u].y;
        s[u].x-=k;
        if (y<1||y>m) continue;
        if (x<1) continue;
        if (x>n) x=n;
        while (1)
        {
            x=find01(0,x,y);
            if (x<1||x<s[u].x) break;
            Del(x,y);
        }
    }
}
void down (int k)//所以的障碍下走k步
{
    for (int u=1;u<=e;u++)
    {
        int x=s[u].x,y=s[u].y;
        s[u].x+=k;
        if (y<1||y>m) continue;
        if (x>n) continue;
        if (x<1) x=1;
        while (1)
        {
            x=find01(1,x,y);
            if (x>n||x>s[u].x) break;
            Del(x,y);
        }
    }
}
void left (int k)//所有障碍往左走k步
{
    for (int u=1;u<=e;u++)
    {
        int x=s[u].x,y=s[u].y;
        s[u].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<s[u].y) break;
            Del(x,y);
        }
    }
}
void right (int k)//所有障碍往右走k步
{
    for (int u=1;u<=e;u++)
    {
        int x=s[u].x,y=s[u].y;
        s[u].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>s[u].y) break;
            Del(x,y);
        }
    }
}
int main()
{
    memset(ok,true,sizeof(ok));
    scanf("%d%d%d%d",&n,&m,&e,&q);
    for (int u=0;u<=n+1;u++)//一定要超出边界
        for (int i=0;i<=m+1;i++)//一定要超出边界 
            f[0][u][i]=f[1][u][i]=u,f[2][u][i]=f[3][u][i]=i;
    for (int u=1;u<=e;u++)  
    {
        scanf("%d%d",&s[u].x,&s[u].y);
        Del(s[u].x,s[u].y);
    }
    for (int u=1;u<=m;u++) s[++e]={0,u},s[++e]={n+1,u};
    for (int u=1;u<=n;u++) s[++e]={u,0},s[++e]={u,m+1};
    while (q--)
    {
        char ss[10];int k;
        scanf("%s%d",ss,&k);
            ans=0;
        if (ss[0]=='U') down (k);
        if (ss[0]=='D') up(k);
        if (ss[0]=='L') right(k);
        if (ss[0]=='R') left(k);

        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值