P10096 [ROIR 2023 Day 1] 扫地机器人

一个扫地机器人正在清洁一个二维坐标平面。扫地机器人是一个边长 k\times kk×k 的正方形,边与坐标轴平行。初始时,扫地机器人左下角位于 (0,0)(0,0),右上角位于 (k,k)(k,k)。

题目描述
给定一个由 nn 个移动操作组成的序列,第 ii 个移动操作由方向 d_id
i

(N 表示向上,增加 yy 坐标;E 表示向右,增加 xx 坐标;W 表示向左,减小 xx 坐标;S 表示向下,减小 yy 坐标)和距离 a_ia
i

(机器人移动的距离)组成。根据给定的机器人移动操作,计算清扫的总面积(被机器人覆盖过的点就算被清扫过的点)。

输入格式
第一行包含两个整数,机器人的大小 kk 和操作数量 nn。

接下来的 nn 行中,每行包含一个移动操作和对应的距离 a_ia
i

。移动操作用字母 d_id
i

表示(N 即向上,E 即向右,W 即向左,S 即向下),且距离 a_ia
i

是一个整数。

输出格式
输出机器人清扫的总面积。

输入输出样例
输入 #1复制
1 5
E 2
N 2
W 4
S 4
E 4
输出 #1复制
17
输入 #2复制
3 4
W 2
N 1
W 1
N 2
输出 #2复制
27
说明/提示
样例解释:下图是两个样例中机器人的移动情况。

本题使用捆绑测试。

对于 100%100% 数据,1 \le k \le 10^41≤k≤10
4
,1 \le n \le 10^51≤n≤10
5
,1 \le a_i \le 10^91≤a
i

≤10
9

注意:机器人可能会走过它之前走过的区域。

#include<bits/stdc++.h>
#define int long long
using namespace std;
namespace IAOI_lib{
  class atlantis{
    typedef pair<int,int> pii;
    typedef tuple<int,int,int,int> tpi;
    private:
      struct Line{
        int l,r,h,s;
        bool operator <(const Line &x)const{
          return h<x.h;
        }
      };
      int n;
      vector<Line> L;
      vector<pii> B;
      vector<int> X,C,S;
      void build(int u,int l,int r){
        if(B[u]=make_pair(l,r);l==r)return;
        int m=l+r>>1;
        build(u<<1,l,m),build(u<<1|1,m+1,r);
        pushup(u);
      };
      void pushup(int u){
        if(C[u])S[u]=X[B[u].second+1]-X[B[u].first];
        else S[u]=S[u<<1]+S[u<<1|1];
      }
      void update(int u,int l,int r,int c){
        if(X[B[u].second+1]<=l||r<=X[B[u].first])return;
        if(l<=X[B[u].first]&&X[B[u].second+1]<=r)C[u]+=c;
        else update(u<<1,l,r,c),update(u<<1|1,l,r,c);
        pushup(u);
      }
      int all_prod(){return S[1];}
    public:
      int areas_union(vector<tpi> &a){
        X.resize(a.size()<<1),L.resize(a.size()<<1);
        for(int i=0;i<a.size();i++){
          auto &[xa,ya,xb,yb]=a[i];
          if(xa>xb)swap(xa,xb); if(ya>yb)swap(ya,yb);
          X[i<<1]=xa,X[i<<1|1]=xb;
          L[i<<1]=(Line){xa,xb,ya,1},L[i<<1|1]=(Line){xa,xb,yb,-1};
        }
        sort(L.begin(),L.end(),[](Line x,Line y){return x.h<y.h;});
        sort(X.begin(),X.end()),n=unique(X.begin(),X.end())-X.begin();
        B.resize(n<<2),C.resize(n<<2),S.resize(n<<3),build(1,0,n-2);
        int c=0;
        for(int i=0;i+1<a.size()<<1;i++){
          update(1,L[i].l,L[i].r,L[i].s);
          c+=all_prod()*(L[i+1].h-L[i].h);
        }
        return c;
      }
  };
} // 扫描线模板
main(){
  ios::sync_with_stdio(false);
  int k,n; cin>>k>>n;
  vector<tuple<int,int,int,int> > a;
  int x=0,y=0; a.emplace_back(0,0,k,k);
  while(n--){
    char c; int d; cin>>c>>d;
    switch(c){
      case 'N':a.emplace_back(x,y,x+k,y+d+k),y+=d; break;
      case 'E':a.emplace_back(x,y,x+d+k,y+k),x+=d; break;
      case 'W':a.emplace_back(x-d,y,x+k,y+k),x-=d; break;
      default:a.emplace_back(x,y-d,x+k,y+k),y-=d;
    }
  } // 依次处理每一条指令
  cout<<IAOI_lib::atlantis().areas_union(a)<<endl;
  return 0;
}
  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值