题解:P8734 [蓝桥杯 2020 国 A] 奇偶覆盖
昨天刚学会扫描线,赶紧来写一篇题解
前置知识:扫描线
还不会扫描线的看这题,本题解不再讲述扫描线的实现。
题意
给出
思路
这题就是扫描线模板稍微改一改
和模板题不一样,这题需要维护两个区间长度(奇数次覆盖和偶数次覆盖)。
看到很多题解都这么做了,维护 感觉好麻烦
我很懒,所以不想改动板子,所以想出来一个相对简单一些的做法:
模板里的总长度
现在考虑如何维护奇数次覆盖长度
分三种情况:
1.区间没被覆盖:左右儿子相加即可。
2.区间覆盖次数为奇数:奇
3.区间覆盖次数为偶数:偶
上述所有操作在 pushup 函数内实现:
void push_up(int p){
//模板
if(T[p].cover)T[p].len=xx[T[p].r]-xx[T[p].l];
else T[p].len=T[lch].len+T[rch].len;
//奇数次覆盖长度
if(T[p].cover&1)T[p].len1=xx[T[p].r]-xx[T[p].l]-(T[lch].len1+T[rch].len1);//第二种情况
else T[p].len1=T[lch].len1+T[rch].len1;//第一种情况和第三种情况
}
完整代码:
拒绝抄袭代码,共创和谐洛谷
#include<iostream>
#include<algorithm>
#define int long long
#define lch (p<<1)
#define rch (p<<1|1)
using namespace std;
const int N=1e5+10;
struct node{
int l,r,len,len1,cover;
}T[N<<4];//空间开大些保险
struct Line{
int lx,rx,y,inout;
friend bool operator < (const Line &x,const Line &y){
return x.y<y.y;
}
}line[N<<1];
int n,m,xx[N<<1],ans,nx,ny,cnt,k,ans1;
char op;
void push_up(int p){
//模板
if(T[p].cover)T[p].len=xx[T[p].r]-xx[T[p].l];
else T[p].len=T[lch].len+T[rch].len;
//奇数次覆盖长度
if(T[p].cover&1)T[p].len1=xx[T[p].r]-xx[T[p].l]-(T[lch].len1+T[rch].len1);//第二种情况
else T[p].len1=T[lch].len1+T[rch].len1;//第一种情况和第三种情况
}
void build(int p,int l,int r){
T[p].l=l,T[p].r=r,T[p].len=T[p].cover=0;
if(l+1==r)return;
int mid=l+r>>1;
build(lch,l,mid);
build(rch,mid,r);
}
void update(int p,int l,int r,int v){
if(T[p].r<=l||T[p].l>=r)return;
if(T[p].l>=l&&T[p].r<=r){
T[p].cover+=v;
push_up(p);
return;
}
update(lch,l,r,v);
update(rch,l,r,v);
push_up(p);
}
int f(int x){
return lower_bound(xx+1,xx+m+1,x)-xx;
}
void make(int x1,int x2,int y1,int y2){
line[++cnt]=(Line){x1,x2,y1,1};
xx[cnt]=x1;
line[++cnt]=(Line){x1,x2,y2,-1};
xx[cnt]=x2;
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
cin>>n;
for(int x,x1,x2,y1,y2;n--;){
cin>>x1>>y1>>x2>>y2;
make(x1,x2,y1,y2);
}
sort(line+1,line+cnt+1);
sort(xx+1,xx+cnt+1);
m=unique(xx+1,xx+cnt+1)-xx-1;
build(1,1,m);
for(int i=1;i<=cnt;i++){
ans+=T[1].len*(line[i].y-line[i-1].y);
ans1+=T[1].len1*(line[i].y-line[i-1].y);
update(1,f(line[i].lx),f(line[i].rx),line[i].inout);
}
cout<<ans1/*奇数次*/<<"\n"<<ans-ans1/*总面积减去奇数次面积*/<<"\n";
return 0;
}//其他为扫描线模板,不再注释
AC 记录