【学习笔记】扫描线
第一维扫描,第二维数据结构
应用范围:面积并,周长并,二维数点
面积并
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;
}

浙公网安备 33010602011771号