扫描线
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;
}

浙公网安备 33010602011771号