[ROIR 2023 Day 1] 扫地机器人 题解
比较简单的一个扫描线题。
对于每次指令分开考虑,它扫过的一个矩形的四个坐标是好求的。以 N 指令为例,令
最后对于所有指令产生的矩形求面积并即可。
示例代码(使用了本人编写的模板库中的扫描线算法):
#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;
}