矩形面積和矩形周長並的模板——來自notonlysuccess

矩形面積並

hdu1542 Atlantis

題意:矩形面積並
思路:浮點數先要離散化;然後把矩形分成兩條邊,上邊和下邊,對橫軸建樹,然後從下到上掃描上去,用cnt表示該區間下邊比上邊多幾個,sum代表該區間內被覆蓋的線段的長度總和
這裏線段樹的一個結點並非是線段的一個端點,而是該端點和下一個端點間的線段,所以題目中r+1,r-1的地方可以自己好好的琢磨一下
線段樹操作:update:區間增減 query:直接取根節點的值

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
 
const int maxn = 2222;
int cnt[maxn << 2];
double sum[maxn << 2];
double X[maxn];
struct Seg {
	double h , l , r;
	int s;
	Seg(){}
	Seg(double a,double b,double c,int d) : l(a) , r(b) , h(c) , s(d) {}
	bool operator < (const Seg &cmp) const {
		return h < cmp.h;
	}
}ss[maxn];
void PushUp(int rt,int l,int r) {
	if (cnt[rt]) sum[rt] = X[r+1] - X[l];
	else if (l == r) sum[rt] = 0;
	else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		cnt[rt] += c;
		PushUp(rt , l , r);
		return ;
	}
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , c , lson);
	if (m < R) update(L , R , c , rson);
	PushUp(rt , l , r);
}
int Bin(double key,int n,double X[]) {//離散化
	int l = 0 , r = n - 1;
	while (l <= r) {
		int m = (l + r) >> 1;
		if (X[m] == key) return m;
		if (X[m] < key) l = m + 1;
		else r = m - 1;
	}
	return -1;
}
int main() {
	int n , cas = 1;
	while (~scanf("%d",&n) && n) {
		int m = 0;
		while (n --) {
			double a , b , c , d;
			scanf("%lf%lf%lf%lf",&a,&b,&c,&d);//左上和右下
			X[m] = a;
			ss[m++] = Seg(a , c , b , 1);
			X[m] = c;
			ss[m++] = Seg(a , c , d , -1);
		}
		sort(X , X + m);
		sort(ss , ss + m);
		int k = 1;
		for (int i = 1 ; i < m ; i ++) {
			if (X[i] != X[i-1]) X[k++] = X[i];
		}
		memset(cnt , 0 , sizeof(cnt));
		memset(sum , 0 , sizeof(sum));
		double ret = 0;
		for (int i = 0 ; i < m - 1 ; i ++) {
			int l = Bin(ss[i].l , k , X);
			int r = Bin(ss[i].r , k , X) - 1;
			if (l <= r) update(l , r , ss[i].s , 0 , k - 1, 1);
			ret += sum[1] * (ss[i+1].h - ss[i].h);
		}
		printf("Test case #%d\nTotal explored area: %.2lf\n\n",cas++ , ret);
	}
	return 0;
}

矩形周長並

hdu1828 Picture

題意:矩形周長並
思路:與面積不同的地方是還要記錄豎的邊有幾個(numseg記錄),並且當邊界重合的時候需要合併(用lbd和rbd表示邊界來輔助)
線段樹操作:update:區間增減 query:直接取根節點的值

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
 
const int maxn = 22222;
struct Seg{
	int l , r , h , s;
	Seg() {}
	Seg(int a,int b,int c,int d):l(a) , r(b) , h(c) , s(d) {}
	bool operator < (const Seg &cmp) const {
		if (h == cmp.h) return s > cmp.s;
		return h < cmp.h;
	}
}ss[maxn];
bool lbd[maxn<<2] , rbd[maxn<<2];
int numseg[maxn<<2];
int cnt[maxn<<2];
int len[maxn<<2];
void PushUP(int rt,int l,int r) {
	if (cnt[rt]) {
		lbd[rt] = rbd[rt] = 1;
		len[rt] = r - l + 1;
		numseg[rt] = 2;
	} else if (l == r) {
		len[rt] = numseg[rt] = lbd[rt] = rbd[rt] = 0;
	} else {
		lbd[rt] = lbd[rt<<1];
		rbd[rt] = rbd[rt<<1|1];
		len[rt] = len[rt<<1] + len[rt<<1|1];
		numseg[rt] = numseg[rt<<1] + numseg[rt<<1|1];
		if (lbd[rt<<1|1] && rbd[rt<<1]) numseg[rt] -= 2;//兩條線重合
	}
}
void update(int L,int R,int c,int l,int r,int rt) {
	if (L <= l && r <= R) {
		cnt[rt] += c;
		PushUP(rt , l , r);
		return ;
	}
	int m = (l + r) >> 1;
	if (L <= m) update(L , R , c , lson);
	if (m < R) update(L , R , c , rson);
	PushUP(rt , l , r);
}
int main() {
	int n;
	while (~scanf("%d",&n)) {
		int m = 0;
		int lbd = 10000, rbd = -10000;
		for (int i = 0 ; i < n ; i ++) {
			int a , b , c , d;
			scanf("%d%d%d%d",&a,&b,&c,&d);//左下和右上
			lbd = min(lbd , a);
			rbd = max(rbd , c);
			ss[m++] = Seg(a , c , b , 1);
			ss[m++] = Seg(a , c , d , -1);
		}
		sort(ss , ss + m);
		int ret = 0 , last = 0;
		for (int i = 0 ; i < m ; i ++) {
			if (ss[i].l < ss[i].r) update(ss[i].l , ss[i].r - 1 , ss[i].s , lbd , rbd - 1 , 1);
			ret += numseg[1] * (ss[i+1].h - ss[i].h);
			ret += abs(len[1] - last);
			last = len[1];
		}
		printf("%d\n",ret);
	}
	return 0;
}


發佈了31 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章