题意: 矩形覆盖面积奇数次的面积和
思路: 线段树节点每次更新只用看其覆盖奇数次还是偶数次,反转一下即可!!节点的权值也要反转,当前区间长度-上次区间权值 即为节点反转后的权值。仔细想一下即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson (rt<<1)
#define rson ((rt<<1)|1)
#define Mid ((L+R)>>1)
const int MAXN=201000;
struct pos
{
int l,r;
int h,f;
}p[MAXN];
struct node
{
int lazy;
int sum; //边的长度
}tree[MAXN<<2];
int x[MAXN];
int n;
bool cmp(pos a,pos b)
{
return a.h < b.h;
}
void build(int rt,int L,int R)
{
tree[rt].sum=0;
tree[rt].lazy=0;
if(L == R) return ;
build(lson,L,Mid);
build(rson,Mid+1,R);
}
void pushup(int rt,int L,int R)
{
tree[rt].sum=tree[lson].sum+tree[rson].sum;
return ;
}
void pushdown(int rt,int L,int R)
{
if(tree[rt].lazy){
tree[lson].sum=x[Mid]-x[L-1]-tree[lson].sum;
tree[rson].sum=x[R]-x[Mid]-tree[rson].sum;
tree[lson].lazy^=1;
tree[rson].lazy^=1;
tree[rt].lazy=0;
return ;
}
}
void update(int rt,int L,int R,int l,int r,int v)
{
if(l<=L&&R<=r){
tree[rt].lazy^=1;
tree[rt].sum=x[R]-x[L-1]-tree[rt].sum; //每一个节点i的边长都是x[i]-x[i-1]
return ;
}
pushdown(rt,L,R);
if(l<=Mid) update(lson,L,Mid,l,r,v);
if(Mid<r) update(rson,Mid+1,R,l,r,v);
pushup(rt,L,R);
}
int main()
{
int tot=1;
scanf("%d",&n);
for(int i=0;i<n;i++){
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);//输入一个矩形
pos &t1 = p[tot];pos &t2 = p[1+tot];
t1.l = t2.l = x1,t1.r = t2.r = x2;
t1.h = y1;t1.f = 1;
t2.h = y2;t2.f = -1;
x[tot] = x1;x[tot+1] = x2;
tot += 2;
}
sort(p+1,p+tot,cmp);//边按高度从小到大排序(自下而上扫描)
sort(x+1,x+tot);
int k = 1;
for (int i = 2;i < tot;++i)
if (x[i] != x[i-1]) x[++k] = x[i];//去重
build(1,1,k);
ll ans=0;
for(int i=1;i<tot-1;i++){
int l = lower_bound(x+1,x+k,p[i].l) - x;//在横坐标数组里找到这条边的位置
int r = lower_bound(x+1,x+k,p[i].r) - x ;
update(1,1,k,l+1,r,p[i].f); //l+1是将边的长度转换为节点的形式!!
ans+=1ll*tree[1].sum*(p[i+1].h-p[i].h);
}
printf("%lld\n",ans);
return 0;
}