【学习笔记】扫描线

第一维扫描,第二维数据结构
应用范围:面积并,周长并,二维数点

面积并

P5490

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
struct Line{
	int x,l,r;
	int add;
	bool operator<(Line b){
		return x<b.x;
	}
}line[N];int idx;
int len[N<<2],tag[N<<2];
vector<int> lsh;
void push_up(int q,int l,int r){
	if(tag[q]) len[q]=lsh[r]-lsh[l];
	else if(l+1==r) len[q]=0;
	else len[q]=len[q<<1]+len[q<<1|1];
}
void update(int q,int l,int r,int L,int R,int d){
	if(L<=l&&r<=R){
		tag[q]+=d;
		push_up(q,l,r);
		return ;
	}
	if(l+1==r) return ;
	int mid=l+r>>1;
	if(L<mid) update(q<<1,l,mid,L,R,d);
	if(mid<R) update(q<<1|1,mid,r,L,R,d);
	push_up(q,l,r);
}
signed main(){
	int n;cin>>n;
	for(int i=1;i<=n;i++){
		int xx1,xx2,yy1,yy2;
		cin>>xx1>>yy1>>xx2>>yy2;
		line[++idx]={xx1,yy1,yy2,1};
		line[++idx]={xx2,yy1,yy2,-1};
		lsh.push_back(yy1);
		lsh.push_back(yy2);
	}
	lsh.push_back(-1);
	sort(lsh.begin(),lsh.end());lsh.erase(unique(lsh.begin(),lsh.end()),lsh.end());
	for(int i=1;i<=idx;i++){
		line[i].l=lower_bound(lsh.begin(),lsh.end(),line[i].l)-lsh.begin();
		line[i].r=lower_bound(lsh.begin(),lsh.end(),line[i].r)-lsh.begin();
	}
	sort(line+1,line+1+idx);
	int ans=0;
	for(int i=1;i<=idx;i++){
		ans+=len[1]*(line[i].x-line[i-1].x);
		update(1,1,lsh.size(),line[i].l,line[i].r,line[i].add);
	}
	cout<<ans<<"\n";
	return 0;
}

周长并

P1856

注意边界重合情况,这里的处理方式是按照add作第二关键字排序,其他的和面积并类似

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;int n;
struct read{
	int r1,r2,r3,r4;
}sca[N];
struct Line{
	int x,l,r;
	int add;
	bool operator<(Line b){
		if(x!=b.x) return x<b.x;
		return add>b.add;
	}
}line[N];int idx;
int len[N<<2],tag[N<<2];
void push_up(int q,int l,int r){
	if(tag[q]) len[q]=r-l;
	else if(l+1==r) len[q]=0;
	else len[q]=len[q<<1]+len[q<<1|1];
}
void update(int q,int l,int r,int L,int R,int d){
	if(L<=l&&r<=R){
		tag[q]+=d;
		push_up(q,l,r);
		return ;
	}
	if(l+1==r) return ;
	int mid=l+r>>1;
	if(L<mid) update(q<<1,l,mid,L,R,d);
	if(mid<R) update(q<<1|1,mid,r,L,R,d);
	push_up(q,l,r);
}
int cl(){
	for(int i=0;i<(N<<2);i++) len[i]=tag[i]=0;
	int idx=0;
	for(int i=1;i<=n;i++){
		int xx1=sca[i].r1,yy1=sca[i].r2,xx2=sca[i].r3,yy2=sca[i].r4;
		line[++idx]={xx1,yy1,yy2,1};
		line[++idx]={xx2,yy1,yy2,-1};
	}
	sort(line+1,line+1+idx);
	int ans=0,las=0;
	for(int i=1;i<=idx;i++){
		update(1,1,2e4,line[i].l,line[i].r,line[i].add);
		ans+=abs(len[1]-las);
		las=len[1];
	}
	return ans;
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		int r1,r2,r3,r4;cin>>r1>>r2>>r3>>r4;
		r1+=1e4;r2+=1e4;r3+=1e4;r4+=1e4;
		sca[i]={r1,r2,r3,r4};
	}
	int ans=cl();
	for(int i=1;i<=n;i++){
		swap(sca[i].r1,sca[i].r2);
		swap(sca[i].r3,sca[i].r4);
	}
	cout<<ans+cl()<<"\n";
	return 0;
}

二维数点(二维偏序)

P10814

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int a[N];
struct Ask{
	int id,r,x;
	int add,ans;
	bool operator<(Ask b){
		return r<b.r;
	}
}ask[N*2];int idx;
int tree[N];
void update(int x,int d){
	while(x<N){
		tree[x]+=d;
		x+=x&-x;
	}
}
int query(int x){
	int res=0;
	while(x){
		res+=tree[x];
		x-=x&-x;
	}
	return res;
}
int as[N];
int main(){
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++){
		int l,r,x;cin>>l>>r>>x;
		ask[++idx]={i,r,x,1,0};
		ask[++idx]={i,l-1,x,-1,0};
	}
	sort(ask+1,ask+1+idx);
	int now=1;
	for(int i=1;i<=idx;i++){
		while(now<=n&&now<=ask[i].r){
			update(a[now],1);
			now++;
		}
		ask[i].ans=query(ask[i].x);
	}
	for(int i=1;i<=idx;i++) as[ask[i].id]+=ask[i].add*ask[i].ans;
	for(int i=1;i<=m;i++) cout<<as[i]<<"\n";
	return 0;
}
posted @ 2025-12-29 08:28  Ming3398  阅读(1)  评论(0)    收藏  举报