扫描线
其实并不能很熟练的写出代码,开此博客简单整理一下代码实现。
扫描线使用线段树的操作来实现。
对于这个线段树,可不是简单的线段树。我们维护的区间也很神奇……
对于 \(l,r\) 我们其实维护的是区间 \(\left[que[l],que[r+1]\right)\)
因为对于每一个区间加操作,一定会有一个相对应的区间减操作,所以标记不必下移,也不必更新……
在对边进行排序的时候,需要按照两个关键字进行排序
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
#define mid (l+r>>1)
using namespace std;
int read()
{
int a = 0,x = 1;char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') x = -1;ch = getchar();}
while(ch >= '0' && ch <= '9') {a = a*10 + ch-'0';ch = getchar();}
return a*x;
}
const int N=1e6+7;
struct node{
int l,r,h,x;
friend bool operator < (node a,node b) {return a.h!=b.h?a.h < b.h:a.x>b.x;}
}arr[N];
int n,cnt,que[N],tot,ans;
int a[N],b[N],c[N],d[N];
int tre[N],lazy[N];
void pushup(int root,int l,int r)
{
if(lazy[root]) tre[root] = que[r+1]-que[l];
else tre[root] = tre[root<<1]+tre[root<<1|1];
}
void modify(int root,int l,int r,int L,int R,int x)
{
if(que[l] >= R || que[r+1] <= L) return;
if(que[l] >= L && que[r+1] <= R) {
lazy[root] += x;
} else {
modify(root<<1,l,mid,L,R,x);
modify(root<<1|1,mid+1,r,L,R,x);
}
pushup(root,l,r);
}
void solve()
{
for(int i = 1,tmp=0;i <= tot;i ++) {
modify(1,1,cnt-1,arr[i].l,arr[i].r,arr[i].x);
ans += abs(tmp-tre[1]);
tmp = tre[1];
}
}
signed main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
n = read();
for(int i = 1;i <= n;i ++) {
a[i] = read(),b[i] = read(),c[i] = read(),d[i] = read();
}
for(int i = 1;i <= n;i ++){
que[++cnt] = a[i],que[++cnt] = c[i];
arr[++tot] = (node){a[i],c[i],b[i],1};
arr[++tot] = (node){a[i],c[i],d[i],-1};
}
sort(que+1,que+1+cnt);
cnt = unique(que+1,que+1+cnt) - que - 1;
que[0] = -1e18,que[cnt+1] = 1e18;
sort(arr+1,arr+1+tot);
solve();
tot = cnt = 0;
for(int i = 1;i <= n;i ++){
que[++cnt] = b[i],que[++cnt] = d[i];
arr[++tot] = (node){b[i],d[i],a[i],1};
arr[++tot] = (node){b[i],d[i],c[i],-1};
}
sort(que+1,que+1+cnt);
cnt = unique(que+1,que+1+cnt) - que - 1;
que[0] = -1e18,que[cnt+1] = 1e18;
sort(arr+1,arr+1+tot);
solve();
printf("%lld",ans);
return 0;
}