本来想写线段树的,感觉太麻烦,于是写了 map 存下区间然后暴力扫的 O(n2) 扫描线的做法。本想着再卡卡常,结果跑这么快。
后来想了想,这个最坏 O(n2) 的做法如果不有意卡的话,可以跑到的期望是 O(nn) 对吧。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#define ll long long
#define uns unsigned
#define MAXN 5005
#define INF 1e17
#define lowbit(x) ((x)&(-(x)))
#define IF it->first
#define IS it->second
using namespace std;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar();
return f?x:-x;
}
int n,Q,m;
struct itn{
int l,r;itn(){}
itn(int L,int R){l=L,r=R;}
bool operator<(const itn&b)const{
if(l!=b.l)return l<b.l;
else return r<b.r;
}
};
pair<int,itn>pr,e[MAXN<<1];
map<itn,int>mp;
map<itn,int>::iterator it;
signed main()
{
n=read(),m=0;
for(int i=1;i<=n;i++){
int x=read(),y=read(),x_=read(),y_=read();
pr.first=y,pr.second=itn(x,x_),e[++m]=pr;
pr.first=y_,pr.second=itn(x_,x),e[++m]=pr;
}
sort(e+1,e+1+m);
mp.clear();
ll s=0,bf=-20000,ans=0;
for(int i=1;i<=m;i++){
int y=e[i].first,l=e[i].second.l,r=e[i].second.r;
int iv=1;
if(l>r)swap(l,r),iv=-1;
ans+=s*(y-bf),bf=y;
if(iv<0){
mp[itn(l,r)]+=iv;
if(mp[itn(l,r)]==0)mp.erase(itn(l,r));
}
int lt=-20000,rt=-20000,len=r-l;
for(it=mp.begin();it!=mp.end();it++){
if(IF.l<=rt)rt=max(rt,IF.r);
else len-=max(min(r,rt)-max(l,lt),0),lt=IF.l,rt=IF.r;
}
len-=max(min(r,rt)-max(l,lt),0),ans+=len;
if(iv>0)mp[itn(l,r)]+=iv;
lt=-20000,rt=-20000;s=0;
for(it=mp.begin();it!=mp.end();it++){
if(IF.l<=rt)rt=max(rt,IF.r);
else s+=2,lt=IF.l,rt=IF.r;
}
}
printf("%lld\n",ans);
return 0;
}