一道經典的掃描線+線段樹求矩形面積並的題目
用線段樹維護y,記錄所有線段被覆蓋的次數和長度,掃描線維護x,把一個長方形拆成兩個事件,左邊界作爲+1,右邊界作爲-1,即可利用線段樹進行維護。
非離散化版本:
#include<iostream>
#include<algorithm>
using namespace std;
#define lson k<<1
#define rson k<<1|1
const int maxn=1005;
const int maxm=50005;
struct event
{
int x,y1,y2,add;
}eve[maxn<<1];
bool cmp(const event &a,const event &b)
{
return a.x<b.x;
}
struct node
{
int sum,cnt;
}tree[maxm<<2];
void pushup(int k,int l,int r)
{
tree[k].sum=tree[lson].sum+tree[rson].sum;
if(tree[k].cnt)
tree[k].sum=r-l;
}
void update(int k,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
tree[k].cnt+=v;
pushup(k,l,r);
return ;
}
int mid=l+r>>1;
if(R<=mid)
update(lson,l,mid,L,R,v);
else if(L>=mid)
update(rson,mid,r,L,R,v);
else
{
update(lson,l,mid,L,mid,v);
update(rson,mid,r,mid,R,v);
}
pushup(k,l,r);
}
int main()
{
ios_base::sync_with_stdio(0);
int x1,x2,y1,y2;
while(cin>>x1>>y1>>x2>>y2)
{
if(x1+x2+y1+y2==-4)
break;
int all=0;
int n=0;
while(x1+x2+y1+y2!=-4)
{
n=max(n,y2);
eve[++all].x=x1,eve[all].y1=y1,eve[all].y2=y2,eve[all].add=1;
eve[++all].x=x2,eve[all].y1=y1,eve[all].y2=y2,eve[all].add=-1;
cin>>x1>>y1>>x2>>y2;
}
sort(eve+1,eve+all+1,cmp);
update(1,0,n,eve[1].y1,eve[1].y2,eve[1].add);
long long ans=0;
for(int i=2;i<=all;i++)
{
ans+=1ll*(eve[i].x-eve[i-1].x)*tree[1].sum;
update(1,0,n,eve[i].y1,eve[i].y2,eve[i].add);
}
cout<<ans<<endl;
}
return 0;
}
離散化版本:
#include<iostream>
#include<algorithm>
using namespace std;
#define lson k<<1
#define rson k<<1|1
const int maxn=1005;
const int maxm=50005;
struct event
{
int x,y1,y2,add;
}eve[maxn<<1];
bool cmp(const event &a,const event &b)
{
return a.x<b.x;
}
struct node
{
int sum,cnt;
}tree[maxm<<2];
struct rectangle
{
int x1,y1,x2,y2;
}rec[maxn];
int id[maxn<<1];
void pushup(int k,int l,int r)
{
tree[k].sum=tree[lson].sum+tree[rson].sum;
if(tree[k].cnt)
tree[k].sum=id[r]-id[l];
}
void update(int k,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
tree[k].cnt+=v;
pushup(k,l,r);
return ;
}
int mid=l+r>>1;
if(R<=mid)
update(lson,l,mid,L,R,v);
else if(L>=mid)
update(rson,mid,r,L,R,v);
else
{
update(lson,l,mid,L,mid,v);
update(rson,mid,r,mid,R,v);
}
pushup(k,l,r);
}
int main()
{
ios_base::sync_with_stdio(0);
int x1,x2,y1,y2;
while(cin>>x1>>y1>>x2>>y2)
{
if(x1+x2+y1+y2==-4)
break;
int all=0;
while(x1+x2+y1+y2!=-4)
{
rec[++all].x1=x1,rec[all].x2=x2,rec[all].y1=y1,rec[all].y2=y2;
cin>>x1>>y1>>x2>>y2;
}
for(int i=1;i<=all;i++)
{
id[i]=rec[i].y1,id[i+all]=rec[i].y2;
}
sort(id+1,id+2*all+1);
for(int i=1;i<=all;i++)
{
rec[i].y1=lower_bound(id+1,id+2*all+1,rec[i].y1)-id;
rec[i].y2=lower_bound(id+1,id+2*all+1,rec[i].y2)-id;
eve[i].add=1,eve[i+all].add=-1;
eve[i].x=rec[i].x1,eve[i+all].x=rec[i].x2;
eve[i].y1=eve[i+all].y1=rec[i].y1;
eve[i].y2=eve[i+all].y2=rec[i].y2;
}
sort(eve+1,eve+2*all+1,cmp);
update(1,1,2*all,eve[1].y1,eve[1].y2,eve[1].add);
long long ans=0;
for(int i=2;i<=2*all;i++)
{
ans+=1ll*(eve[i].x-eve[i-1].x)*tree[1].sum;
update(1,1,2*all,eve[i].y1,eve[i].y2,eve[i].add);
}
cout<<ans<<endl;
}
return 0;
}
其實是否離散化對於線段樹來說幾乎沒有區別,此處維護線段長度的線段樹與普通維護區間的線段樹不太一樣,在進行分治的時候需要特別注意參數的傳遞。