萌新妹子求助简单扫描线/kk
查看原帖
萌新妹子求助简单扫描线/kk
227728
冰糖鸽子TJ鸽子协会楼主2021/8/10 21:14

RT,扫描线从下往上扫,用区间min是否为0来处理线段树询问。


// Problem: P5490 【模板】扫描线
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5490
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;
#define M 100005
#define int long long
#define ls (i*2)
#define rs (i*2+1)
#define mid ((L+R)/2)
int n,len,ans,cntp;
int w[M],a[M];
const int inf=1e17+7;
map<int,int>id,fid;//离散化用
struct node
{int ax,bx,ay,by,op,fp;}sq[M],eg[M*3];
//eg存每一条横边,by是这条线的高度
//ax和bx是这条线的两个端点,ax<=bx
struct noda
{int laz,ini,axi,ll,rr,sum;}t[10*M];
/*"minimum" can be "min"*/
/*So why can't be "ini"*/
bool cmp(node A,node B) {return A.by<B.by;}
int max(int A,int B) {return A>B?A:B;}
int min(int A,int B) {return A<B?A:B;}
void buildt(int L,int R,int i)
{
	cntp++,t[i].ll=L,t[i].rr=R;
	if(L==R) {t[i].sum=w[L];return;} //sum就是这段区间的长度,后面不会变了
	buildt(L,mid,ls),buildt(mid+1,R,rs);
	t[i].sum=t[ls].sum+t[rs].sum; return;
}
void pd(int i) /*下传标记*/
{
	if(t[i].laz==0) return ;
	int fp=t[i].laz; t[i].laz=0;
	t[ls].laz+=fp,t[rs].laz+=fp;
	t[ls].ini+=fp,t[ls].axi+=fp;
	t[rs].ini+=fp,t[rs].axi+=fp;
	return;
}
int gt(int x) {return (x<=cntp?t[x].ini:inf);}
int Gt(int x) {return (x<=cntp?t[x].axi:-inf);}
void plused(int wl,int wr,int L,int R,int i,int x)//将[wl-wr]的cnt+x
{
	if(wr<wl) return; // 防止出现奇怪情况
	if(wl<=L&&wr>=R)
	{
		t[i].laz+=x,t[i].ini+=x,t[i].axi+=x;//ini和axi显然也是+x
		return;
	}
	pd(i);
	if(wl<=mid) plused(wl,wr,L,mid,ls,x);//线段树基本操作
	if(wr>mid) plused(wl,wr,mid+1,R,rs,x);
	/*下面防止访问到值不确定的地方*/
	t[i].ini=min(gt(i*2),gt(i*2+1)),t[i].axi=max(Gt(i*2),Gt(i*2+1)); return;
}
int Query(int L,int R,int i)
{
	if(t[i].ini>0) return t[i].sum; //如果min值>0,即区间无0,则整个区间都被覆盖了
	pd(i); int res=0;
	if(t[ls].axi) res+=Query(L,mid,ls); //左子树有需要累加的
	if(t[rs].axi) res+=Query(mid+1,R,rs); //右子树有需要累加的
	return res;
}
int Ins_up(int ind)
{
	plused(id[eg[ind].ax],id[eg[ind].bx]-1,1,len,1,eg[ind].op);
	return Query(1,len,1); // 先加上(或减去)这条边,然后求一下矩形宽
}   
signed main()
{
	cin>>n; int X,Y,XX,YY;
	for(int i=1;i<=n;i++)
		cin>>X>>Y>>XX>>YY,sq[i].ax=X,sq[i].bx=XX,sq[i].ay=Y,sq[i].by=YY,
		eg[i*2-1].ax=eg[i*2].ax=X,
		eg[i*2-1].bx=eg[i*2].bx=XX,
		eg[i*2-1].fp=eg[i*2].fp=i,
		eg[i*2-1].by=Y,eg[i*2-1].op=1,
		eg[i*2].by=YY,eg[i*2].op=-1,
		a[i*2-1]=X,a[i*2]=XX;
	/*
	以上八行输入+阶段处理
	*/
	sort(eg+1,eg+2*n+1,cmp); sort(a+1,a+2*n+1); len=unique(a+1,a+2*n+1)-(a+1);
	for(int i=1;i<=len;i++) id[a[i]]=i,fid[i]=a[i],w[i]=a[i+1]-a[i];
	/*以上两行离散化*/
	len--; buildt(1,len,1);//建树
	for(int i=1;i<2*n;i++)//因为最上面的边无对应矩形,所以到2*n
	{
		//累计一个矩形
		ans+=(eg[i+1].by-eg[i].by)*Ins_up(i);
	}
	cout<<ans<<endl;
	return 0;
}
2021/8/10 21:14
加载中...