luoguP8734
luoguP8734
前置芝士:P5490【模板】扫描线
思路
首先,这题肯定是扫描线,然而题解区都是写的离散化线段树,我就来写一个动态开点的线段树。
接着,来分析一下题面,这题让我们分别求出被奇次覆盖的方格数与偶次覆盖的方格数,那么就要在模板扫描线的基础上,将区间覆盖数拆成区间奇次覆盖数与区间偶次覆盖数(不包括 \(0\) 次覆盖),那么在 pushup 时就要改动一下。
void push_up(int x,int l,int r){
if(!tr[x].fg){//区间无覆盖标记:由左右儿子加来
tr[x].j=tr[tr[x].l].j+tr[tr[x].r].j;
tr[x].o=tr[tr[x].l].o+tr[tr[x].r].o;
return ;
}
if(tr[x].fg&1){//区间标记为奇数:区间奇偶覆盖数互换
tr[x].o=tr[tr[x].l].j+tr[tr[x].r].j;
tr[x].j=r-l+1-tr[x].o;
}
else{//区间标记为偶数:区间奇偶覆盖数不变
tr[x].j=tr[tr[x].l].j+tr[tr[x].r].j;
tr[x].o=r-l+1-tr[x].j;
}
}
剩下的就与正常扫描线一样了,具体见代码。
code
#include<bits/stdc++.h>
//#define int long long 别都开long long,不然MLE送给你
using namespace std;
inline int read(){
char c=getchar();
int ret=0,f=1;
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ret=(ret<<3)+(ret<<1)+c-'0';
c=getchar();
}return ret*f;
}
inline void write(long long x,int op){//write要开long long,因为答案输出要long long
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10,0);
putchar((char)(x%10+'0'));
if(op){
if(op>0)puts("");
if(op<0)putchar(' ');
if(op==0)puts("114514");
}
}
const int N=1e7+10;
int n,tot,cnt=1,last;
long long ansj,anso;//答案超过了int范围,要开long long
struct node{
int t,fg;
int j,o;
int l,r;
}tr[N];
struct Node{
int x,y,_y,z;
}a[N];
bool cmp(Node x,Node y){
return x.x<y.x;
}
void build(int l,int r,int x,int op){
int id=++cnt;
if(op==1)tr[x].l=cnt;
else tr[x].r=cnt;
}
void push_up(int x,int l,int r){
if(!tr[x].fg){//区间无覆盖标记:由左右儿子加来
tr[x].j=tr[tr[x].l].j+tr[tr[x].r].j;
tr[x].o=tr[tr[x].l].o+tr[tr[x].r].o;
return ;
}
if(tr[x].fg&1){//区间标记为奇数:区间奇偶覆盖数互换
tr[x].o=tr[tr[x].l].j+tr[tr[x].r].j;
tr[x].j=r-l+1-tr[x].o;
}
else{//区间标记为偶数:区间奇偶覆盖数不变
tr[x].j=tr[tr[x].l].j+tr[tr[x].r].j;
tr[x].o=r-l+1-tr[x].j;
}
}
void gx(int id,int l,int r,int x,int y,int v){
if(x<=l&&r<=y){
tr[id].fg+=v;//增加标记
push_up(id,l,r);
return ;
}int mid=(l+r)>>1;
if(x<=mid){
if(!tr[id].l)build(l,mid,id,1);//动态开点
gx(tr[id].l,l,mid,x,y,v);
}
if(mid<y){
if(!tr[id].r)build(mid+1,r,id,2);//动态开点+1
gx(tr[id].r,mid+1,r,x,y,v);
}push_up(id,l,r);
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
int aa,bb,cc,dd;
cin>>bb>>aa>>dd>>cc;
a[++tot].x=aa;//记录扫描线
a[tot].y=bb;
a[tot]._y=dd;
a[tot].z=1;
a[++tot].x=cc;
a[tot].y=bb;
a[tot]._y=dd;
a[tot].z=-1;
}sort(a+1,a+1+tot,cmp);//排一下序
gx(1,0,1000000000,a[1].y,a[1]._y-1,1),last=a[1].x;//更新上下界为0道1e9
for(int i=2;i<=tot;i++){
if(a[i].x!=last){
ansj+=1ll*(a[i].x-last)*(tr[1].j);//应为a[i].x与last都为int,所以要*1ll
anso+=1ll*(a[i].x-last)*(tr[1].o);//分别统计奇偶答案
last=a[i].x;
}
gx(1,0,1000000000,a[i].y,a[i]._y-1,a[i].z);
}write(ansj,1),write(anso,0);
return 0;
}//~*完结撒花*~

浙公网安备 33010602011771号