扫描线

Sample 1


Question:

给定\(n\)个修改,\(q\)个查询,每次修改让一个矩形的所有整数点权值\(+1\),每次询问二维坐标系下\((x,y)\)点的权值。
对于\(100\%\)的数据,保证\(1 \le n,m,x_1,x_2,y_1,y_2 \le 10^5\)

Sol

注意到区间修改,单点查询是差分干的事。一个显然的二维差分。
然后思考如何维护权值。
对于矩形,我们可以想到扫描线的做法。
用树状数组维护当前区间内小于等于当前\(y\)坐标的点数计算即可。

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int M=1e5+5;
int c[M],ans[M];
int lowbit(int k){return k&(-k);}
int query(int x){
    int res=0;
    for(;x;x-=lowbit(x))res+=c[x];
    return res;
}
void modify(int x,int y){
    for(;x<M;x+=lowbit(x))c[x]+=y;
}
struct node{
    int x,y,id,st;
    node(int a=0,int b=0,int c=0,int d=0){
        x=a,y=b,id=d,st=c;
    }
    bool operator < (const node &a)const{
        if(x==a.x) return id<a.id;
        return x<a.x;
    }
};
vector<node>T;
int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        T.push_back(node(x1,y1,1,-1));
        T.push_back(node(x1,y2+1,-1,-1));
        T.push_back(node(x2+1,y1,-1,-1));
        T.push_back(node(x2+1,y2+1,1,-1));
    }
    for(int i=1;i<=q;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        T.push_back(node(x,y,0,i));
    }
    sort(T.begin(),T.end());
    for(int x=1,j=0;x<M;x++){
        while(T[j].x<=x&&j<T.size()){
            if(T[j].id!=-1)ans[T[j].id]=query(T[j].y);
            else modify(T[j].y,T[j].st); 
            j++;
        }
    }
    for(int i=1;i<=q;i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}

Sample 2

Question:

\(n\) 个四边平行于坐标轴的矩形的面积并。
对于 \(100\%\) 的数据,\(1 \le n \le {10}^5\)\(0 \le x_1 < x_2 \le {10}^9\)\(0 \le y_1 < y_2 \le {10}^9\)

Sol

有了上一题经验,还是可以把矩形拆成两条线,左侧+1,右侧-1。
我们想到按照\(x\)轴排序,每次区间加,然后答案加上两次\(x\)坐标之差乘以区间总和。
注意题目中线段树比较特殊,详见代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int M=1e5+5;
struct Seg{
	int l,r,cov;
	ll len;
}Tree[M<<4];
int v[M<<1];
struct node{
	int x,y1,y2,state;
	bool operator <(node a){return x<a.x;}
}line[M<<2];
void push_up(int p){
	if(Tree[p].cov)Tree[p].len=Tree[p].r-Tree[p].l;
	else Tree[p].len=Tree[p<<1].len+Tree[p<<1|1].len;
}
void build(int p,int l,int r){
	Tree[p].l=v[l],Tree[p].r=v[r];
	if(r-l<=1)return;
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid,r);
}
void modify(int p,int ql,int qr,int k){
	int l=Tree[p].l,r=Tree[p].r;
	if(ql<=l&&qr>=r){
		Tree[p].cov+=k;
		push_up(p);
		return;
	}
	if(ql<Tree[p<<1].r)modify(p<<1,ql,qr,k);
	if(qr>Tree[p<<1|1].l)modify(p<<1|1,ql,qr,k);
	push_up(p);
}
int main(){
	clock_t st=clock();
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int a,b,c,d;
		scanf("%d%d%d%d",&a,&b,&c,&d);
		v[i]=b,v[n+i]=d;
		line[i]=(node){a,b,d,1},line[n+i]=(node){c,b,d,-1};
	}
	sort(v+1,v+1+(n<<1));
	sort(line+1,line+1+(n<<1));
	build(1,1,(n<<1));
	ll ans=0;
	for(int i=1;i<=(n<<1);i++){
		ans+=Tree[1].len*(line[i].x-line[i-1].x);
		modify(1,line[i].y1,line[i].y2,line[i].state);
	}
	printf("%lld",ans);
	clock_t ed=clock();
	cerr<<'\n'<<ed-st<<"ms"<<endl;
	return 0;
}
posted @ 2025-11-08 23:23  nick_zha  阅读(7)  评论(0)    收藏  举报