加了些注释
- 2 WA 8 TLE
- 不很清楚自己的做法是否正确
#include <bits/stdc++.h>
using namespace std;
int n;
int num;
int tmp_[400005];
struct node{
int l,r,len,ti;
//ti表示被完整覆盖的次数
//len表示被截取的长度
}t[800005];
struct line_{
int dy,x1,x2;
bool v;
}a[200005];
int cnt;
int f[400005];
inline int ls(int p){return p<<1;}
inline int rs(int p){return p<<1|1;}
void built(int p,int l,int r){
//对于一个点的情况没必要记录
if(l==r) return;
t[p].l=l,t[p].r=r;
//l+1==r,说明但前是叶子结点,记录最小线段的状态
if(l+1==r) return;
int mid=(r-l>>1)+l;
//原区间[l,r]拆分为[l,mid][mid,r]
built(ls(p),l,mid);
built(rs(p),mid,r);
}
bool cmp(line_ x,line_ y){
if(x.dy==y.dy) return x.v>y.v;
return x.dy<y.dy;
}
int last;
int ans;
int tag[800005];
inline void f_(int p,int k){
tag[p]+=k;
t[p].ti+=k;
t[p].len=f[t[p].r]-f[t[p].l];
}
inline void push_down(int p){
f_(ls(p),tag[p]);
f_(rs(p),tag[p]);
tag[p]=0;
}
inline void push_up(int p){
int l=ls(p),r=rs(p);
t[p].ti=min(t[l].ti,t[r].ti);
//两个叶子结点被完整覆盖的次数的最小值是父亲节点被覆盖的次数
t[p].len=t[l].len+t[r].len;//长度为两个相加
}
inline void add(int p,int rl,int rr,int k){
//没有交集,退出
if(rr<=f[t[p].l]||rl>=f[t[p].r]) return;
if(t[p].l+1==t[p].r){//查询到了叶子结点
if(k==1){
t[p].ti++;//ti表示被完整覆盖的次数
//len表示长度
if(t[p].ti) t[p].len=f[t[p].r]-f[t[p].l];
}
else{
t[p].ti--;
if(!t[p].ti) t[p].len=0;
}
return;
}
if(tag[p]) push_down(p);
add(ls(p),rl,rr,k);
add(rs(p),rl,rr,k);
push_up(p);
}
int main(){
//从下往上扫
scanf("%d",&n);
for(int i=1;i<=n;i++){
int tx1,ty1,tx2,ty2;
scanf("%d%d%d%d",&tx1,&ty1,&tx2,&ty2);
a[++cnt]=(line_){ty1,tx1,tx2,1};
a[++cnt]=(line_){ty2,tx1,tx2,0};
//存储所有的横坐标
tmp_[++num]=tx1;
tmp_[++num]=tx2;
}
cnt=0;
//对横坐标离散化
sort(tmp_+1,tmp_+num+1);
for(int i=1;i<=num;i++){
if(f[cnt]!=tmp_[i])
f[++cnt]=tmp_[i];
//f[l]对应的是这个点的横坐标
}
//建树
built(1,1,cnt);
sort(a+1,a+2*n+1,cmp);
last=a[1].dy;
for(int i=1;i<=2*n;i++){
//每当出现了横边,说明截取的线段长度发生了改变
//这时要计算之前的面积,以及修改线段的状态
if(a[i].v){//新加入了线段
ans+=(a[i].dy-last)*t[1].len;
last=a[i].dy;
add(1,a[i].x1,a[i].x2,1);
}
else{//矩形的上边
ans+=(a[i].dy-last)*t[1].len;
last=a[i].dy;
add(1,a[i].x1,a[i].x2,-1);
}
}
printf("%d\n",ans);
}