線段樹矩形面積並,面積交,周長並
阿新 • • 發佈:2019-02-10
矩形面積交
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 2000+10;
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
struct Rec{
double x1, x2, h;
int d;
bool operator < (const Rec& rhs) const{
return h < rhs.h;
}
}rec[maxn<<2];
struct SegTree{
double sum1, sum2;
int cnt;
}tree[maxn<<2];
double cor[maxn<<2];
// l == r代表沒有子節點了
void pushup(int l,int r,int rt) {
//如果被覆蓋兩次, 那麼久等於整段長度
if(tree[rt].cnt >= 2) {
tree[rt].sum1 = tree[ rt].sum2 = cor[r+1]-cor[l];
}
// 如果只被覆蓋一次, 那麼等於子線段覆蓋之和相加,就成了兩次
else if(tree[rt].cnt == 1) {
if(l == r)
tree[rt].sum2 = 0;
else
tree[rt].sum2 = tree[rt<<1].sum1+tree[rt<<1|1].sum1;
tree[rt].sum1 = cor[r+1]-cor[l];
}
//一次都沒有覆蓋, 那就只能找子線段覆蓋兩次的。
else {
if(l == r)
tree[rt].sum1 = tree[rt].sum2 = 0;
else {
tree[rt].sum1 = tree[rt<<1].sum1+tree[rt<<1|1].sum1;
tree[rt].sum2 = tree[rt<<1].sum2+tree[rt<<1|1].sum2;
}
}
}
void update(int L,int R,int v,int l,int r,int rt) {
if(L > r || R < l) return;
if(L <= l && r <= R) {
tree[rt].cnt += v;
pushup(l,r,rt);
return;
}
int mid = (l+r)>>1;
update(L,R,v,lson);
update(L,R,v,rson);
pushup(l,r,rt);
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
int n;
memset(tree, 0, sizeof tree);
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
rec[i] = Rec{x1,x2,y1,1};
rec[i+n] = Rec{x1,x2,y2,-1};
cor[i] = x1; cor[i+n] = x2;
}
n <<= 1;
sort(rec+1,rec+1+n);
sort(cor+1,cor+1+n);
int m = unique(cor+1,cor+1+n)-cor-1;
double ans = 0;
for(int i = 1; i < n; ++i) {
int lb = lower_bound(cor+1,cor+1+m,rec[i].x1)-cor;
int rb = lower_bound(cor+1,cor+1+m,rec[i].x2)-cor;
if(lb < rb) update(lb,rb-1,rec[i].d,1,m,1);
ans += tree[1].sum2*(rec[i+1].h-rec[i].h);
// cout << rec[i].x1 <<" " << rec[i].x2 << " # ";
// cout <<cor[lb] <<" " << cor[rb] << " ";
// cout << tree[1].sum2 << " " << ans << endl;
}
// ans += 1e-8;
// ans += 0.005;
printf("%.2lf\n", ans);
}
return 0;
}
矩形面積並
#include <bits/stdc++.h>
using namespace std;
const int maxn = 400+10;
const double EPS = 1e-8;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
//線段樹的每個結點儲存的都是一個線段,每個葉子結點實際儲存的是該點到下一個點之間的距離
//所以update的時候需要將r-1
//pushup的時候需要X[r+1]-X[l];
//lazy:代表當前結點的線段被覆蓋多少次
//sum:代表當前結點為根的子樹中被覆蓋的區間一共有多長
struct Rec{
double x1, x2,y;
int d;
Rec(){}
Rec(double x1, double x2, double y, int d):x1(x1),x2(x2),y(y),d(d){}
bool operator < (const Rec& rhs) const {
return y < rhs.y;
}
}r[maxn];
double X[maxn], sum[maxn*4];
int lazy[maxn*4];
int n;
void pushup(int l,int r,int rt) {
if(lazy[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 v, int l, int r, int rt) {
if(L <= l && r <= R) {
lazy[rt] += v;
pushup(l, r, rt);
return;
}
int m = l + r >> 1;
if(L <= m) update(L, R, v, lson);
if(R > m) update(L, R, v, rson);
pushup(l, r, rt);
}
int getid(double x,int mm) {
return lower_bound(X+1,X+mm+1,x)-X;
}
void solve() {
double x1,y1,x2,y2;
while(scanf("%d", &n) && n){
memset(sum, 0, sizeof sum);
memset(lazy, 0, sizeof lazy);
for(int i = 1; i <= n; ++i) {
scanf("%lf%lf%lf%lf", &x1,&y1,&x2,&y2);
r[i] = Rec(x1,x2,y1,1);
r[i+n] = Rec(x1,x2,y2,-1);
X[i] = x1; X[i+n] = x2;
}
n <<= 1;
sort(r+1,r+n+1);
sort(X+1,X+n+1);
int m = int(unique(X+1,X+n+1)-X-1);
double ans = 0;
for(int i = 1; i < n; ++i) {
int lb = getid(r[i].x1,m);
int rb = getid(r[i].x2,m);
// cout << lb <<" " << rb << endl;
if(lb < rb)
update(lb,rb-1,r[i].d,1,m,1);
// cout << sum[1] << endl;
ans += sum[1]*(r[i+1].y-r[i].y);
// cout << ans << endl;
}
printf("%.2lf\n",ans);
}
}
int main() {
solve();
return 0;
}
矩形周長並
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int maxn = 20000+10;
struct Rec {
int x1,x2,h,d;
bool operator < (const Rec& rhs) const {
return h == rhs.h ? d > rhs.d : h < rhs.h;
}
}rec[maxn<<2];
struct SegTree {
int len; // 覆蓋長度
int num; // 豎邊個數
bool lv; // 左端點是否被覆蓋
bool rv;
int cover;
}Seg[maxn<<2];
void pushup(int l,int r,int rt) {
if(Seg[rt].cover) {
Seg[rt].num = 2;
Seg[rt].len = r-l+1;
Seg[rt].lv=Seg[rt].rv=1;
}
else if(l == r) {
Seg[rt].len = Seg[rt].num = Seg[rt].lv = Seg[rt].rv = 0;
}
else {
Seg[rt].lv = Seg[rt<<1].lv;
Seg[rt].rv = Seg[rt<<1|1].rv;
Seg[rt].len = Seg[rt<<1].len + Seg[rt<<1|1].len;
Seg[rt].num = Seg[rt<<1].num + Seg[rt<<1|1].num;
if(Seg[rt<<1|1].lv&&Seg[rt<<1].rv) Seg[rt].num -= 2;
}
}
void update(int L,int R,int v,int l,int r,int rt) {
if(L <= l && r <= R) {
Seg[rt].cover += v;
pushup(l,r,rt);
return;
}
int mid = (l+r)>>1;
if(L <= mid)update(L,R,v,lson);
if(R > mid)update(L,R,v,rson);
pushup(l,r,rt);
}
int main() {
int n;
//freopen("in.txt","r",stdin);
while(~scanf("%d", &n)) {
memset(Seg, 0, sizeof Seg);
int lb = 10000, rb = -10000;
for(int i = 1; i <= n; ++i) {
int x1,x2,y1,y2;
scanf("%d%d%d%d", &x1,&y1,&x2,&y2);
rec[i] = Rec{x1,x2,y1,1};
rec[i+n] = Rec{x1,x2,y2,-1};
lb = min(x1,lb);
rb = max(x2,rb);
}
n <<= 1;
sort(rec+1,rec+1+n);
int ans = 0, pre = 0;
for(int i = 1; i <= n; ++i) {
int l = rec[i].x1, r = rec[i].x2;
// cout << l <<" " << r <<" ";
if(l < r) update(l,r-1,rec[i].d,lb,rb-1,1);
ans += Seg[1].num*(rec[i+1].h-rec[i].h);
//cout << Seg[1].num << " " << Seg[1].len << " " ;
ans += abs(Seg[1].len-pre);
pre = Seg[1].len;
//cout << ans << endl;
}
printf("%d\n", ans)