1. 程式人生 > 實用技巧 >AcWing 247. 亞特蘭蒂斯 (線段樹,掃描線,離散化)

AcWing 247. 亞特蘭蒂斯 (線段樹,掃描線,離散化)

  • 題意:給你\(n\)個矩形,求矩形並的面積.
  • 題解:我們建立座標軸,然後可以對矩形的橫座標進行排序,之後可以遍歷這些橫座標,這個過程可以想像成是一條線從左往右掃過x座標軸,假如這條線是第一次掃過矩形的寬(長)的話,我們就可以在\(y\)軸上對應的區間打上標記,每次列舉的面積就是當前橫座標和上次橫座標的差值乘上目前\(y\)軸上所有打上標記的區間長度\((seg[i].x-seg[i-1].x)*tr[1].len\),y軸上的區間情況我們可以通過線段樹來維護.
  • 程式碼:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}

struct Segment{
	double x,y1,y2;
	int k;
	bool operator < (const Segment & tmp) const {
		return x<tmp.x;
	}
}seg[N*2];

struct Node{
	int l,r;
	int cnt;
	double len;
}tr[8*N];

vector<double> ys;

void push_up(int u){
	if(tr[u].cnt) tr[u].len=ys[tr[u].r+1]-ys[tr[u].l];
	else if(tr[u].l!=tr[u].r){
		tr[u].len=tr[u<<1].len+tr[u<<1|1].len;
	}
	else tr[u].len=0;   //葉子節點並且沒有標記
}

void build(int u,int l,int r){
	tr[u].l=l;
	tr[u].r=r;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
}

void modify(int u,int l,int r,int k){
	if(tr[u].l>=l && tr[u].r<=r){
		tr[u].cnt+=k;
		push_up(u);
	}
	else{
		int mid=(tr[u].l+tr[u].r)>>1;
		if(l<=mid) modify(u<<1,l,r,k);
		if(r>mid) modify(u<<1|1,l,r,k);
		push_up(u);
	}
}

int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n;
	int T=1;
	while(cin>>n){
		if(n==0) break;

		ys.clear();

		int j=0;

		rep(i,0,n-1){
			double x1,y1,x2,y2;
			cin>>x1>>y1>>x2>>y2;
			seg[j++]={x1,y1,y2,1};
			seg[j++]={x2,y1,y2,-1};
			ys.pb(y1),ys.pb(y2);
		}
		
		sort(ys.begin(),ys.end());
		ys.erase(unique(ys.begin(),ys.end()),ys.end());

		build(1,0,ys.size()-2);

		sort(seg,seg+2*n);

		double res=0;

		rep(i,0,2*n-1){    //列舉橫座標  tr[1].len就表示縱座標區間之和
			if(i>0) res+=tr[1].len*(seg[i].x-seg[i-1].x);
			int pos1=lower_bound(ys.begin(),ys.end(),seg[i].y1)-ys.begin();
			int pos2=lower_bound(ys.begin(),ys.end(),seg[i].y2)-ys.begin();
			modify(1,pos1,pos2-1,seg[i].k);
		}

		cout<<"Test case #"<<T++<<'\n';
		cout<<"Total explored area: "<<fixed<<setprecision(2)<<res<<"\n\n";

	}

    return 0;
}