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;
}//~*完结撒花*~
posted @ 2024-07-24 08:23  BriskCube  阅读(24)  评论(0)    收藏  举报