题目链接:点击这里
题目大意:
给出
n
n
n 个矩形的对角坐标求矩形面积的交集
题目分析:
我们考虑用从下而上扫描的扫描线,先要离散化一下
x
x
x 的坐标,来减小线段树的大小
线段树有一些细节:
1.要注意因为线段树维护的是线段长度而不是点权,所以需要做出改变,
[
l
,
r
]
[l,r]
[l,r] 维护的是
x
r
+
1
−
x
l
x_{r+1}-x_l
xr+1−xl
2.因为线段树右端点的意义已经变化了,所以线段树只需要维护
c
n
t
−
1
cnt-1
cnt−1 个元素(
c
n
t
cnt
cnt 为
x
x
x 数组离散化后的元素个数)
3.写
p
u
s
h
u
p
pushup
pushup 时要注意叶子节点没有儿子需要特判,否则会数组越界
最终的答案就是线段树根节点维护的线段长度乘上当前线段与下一条线段的高度差
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
//#define int ll
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 2e5+5;
const int mod = 1e9+7;
const double eps = 1e-8;
struct node{
int sum;ll len;
}a[maxn<<2];
struct Line{
int l,r,h,flag;
bool operator < (const Line &b) const {
return h < b.h;
}
}line[maxn];
int n,X[maxn],val[maxn];
void pushup(int root,int l,int r)
{
if(a[root].sum) a[root].len = X[r+1]-X[l];
else if(l != r)a[root].len = a[root<<1].len+a[root<<1|1].len;
else a[root].len = 0;
}
void updat(int root,int l,int r,int ql,int qr,int val)
{
if(X[l]>=qr || X[r+1]<=ql) return ;
if(X[l]>=ql && X[r+1]<=qr)
{
a[root].sum += val;
pushup(root,l,r);
return ;
}
int mid = l+r>>1;
updat(root<<1,l,mid,ql,qr,val);
updat(root<<1|1,mid+1,r,ql,qr,val);
pushup(root,l,r);
}
int main()
{
n = read();
for(int i = 1;i <= n;i++)
{
int x = read(),y = read(),xx = read(),yy = read();
line[2*i-1] = (Line){x,xx,y,1};
line[2*i] = (Line){x,xx,yy,-1};
X[2*i-1] = x,X[2*i] = xx;
}
n <<= 1;
sort(line+1,line+n+1);
sort(X+1,X+n+1);
int cnt = unique(X+1,X+n+1)-X-1;
ll ans = 0;
for(int i = 1;i < n;i++)
{
updat(1,1,cnt-1,line[i].l,line[i].r,line[i].flag);
ans += a[1].len*(line[i+1].h-line[i].h);
}
printf("%lld\n",ans);
return 0;
}