#include #include using namespace std; using namespace atcoder; using ll=long long; using ull=unsigned long long; using ld=long double; using i128=__int128; using P=pair; template using vc=vector; template using vv=vc>; using vl=vc; using vvl=vc>; using vul=vc; using vs=vc; using vb=vc; #define rep(i,s,n) for(ll i=s;i<(n);i++) #define Rep(i,s,n) for(ll i=n;i>=s;i--) #define nall(x) x.begin(),x.end() #define rall(a) a.rbegin(),a.rend() #define pb push_back #define eb emplace_back #define pob pop_back #define nexp(v) next_permutation(v) #define prep(v) prev_permutation(v) #define YES cout<<"Yes"<b)a=b;} void chmax(ll &a,ll b){if(a struct RangeSet{ set> st; T TINF; RangeSet(){ TINF=numeric_limits::max()/2; st.emplace(TINF,TINF); st.emplace(-TINF,-TINF); } bool covered(T l,T r)const{ assert(l<=r); auto ite=prev(st.lower_bound({l+1,l+1})); return ite->first<=l && r<=ite->second; } bool covered(T x)const{ return covered(x,x); } pair covered_by(T l,T r)const{ assert(l<=r); auto ite=prev(st.lower_bound({l+1,l+1})); if(ite->first<=l && r<=ite->second)return *ite; return make_pair(-TINF,-TINF); } pair covered_by(T x)const{ return covered_by(x,x); } T insert(T l,T r){ assert(l<=r); auto ite=prev(st.lower_bound({l+1,l+1})); if(ite->first<=l && r<=ite->second)return T(0); T sum_erased=T(0); if(ite->first<=l && l<=ite->second+1){ l=ite->first; sum_erased+=ite->second-ite->first+1; ite=st.erase(ite); }else ite=next(ite); while(r>ite->second){ sum_erased+=ite->second-ite->first+1; ite=st.erase(ite); } if(ite->first-1<=r && r<=ite->second){ sum_erased+=ite->second-ite->first+1; r=ite->second; st.erase(ite); } st.emplace(l,r); return r-l+1-sum_erased; } T insert(T x){ return insert(x,x); } T erase(T l,T r){ assert(l<=r); auto ite=prev(st.lower_bound({l+1,l+1})); if(ite->first<=l && r<=ite->second){ if(ite->firstfirst,l-1); if(rsecond)st.emplace(r+1,ite->second); st.erase(ite); return r-l+1; } T ret=T(0); if(ite->first<=l && l<=ite->second){ ret+=ite->second-l+1; if(ite->firstfirst,l-1); ite=st.erase(ite); }else ite=next(ite); while(ite->second<=r){ ret+=ite->second-ite->first+1; ite=st.erase(ite); } if(ite->first<=r && r<=ite->second){ ret+=r-ite->first+1; if(rsecond)st.emplace(r+1,ite->second); st.erase(ite); } return ret; } T erase(T x){ return erase(x,x); } int size()const{ return (int)st.size()-2; } T mex(T x=0)const{ auto ite=prev(st.lower_bound({x+1,x+1})); if(ite->first<=x && x<=ite->second)return ite->second+1; return x; } void output()const{ cout<<"RangeSet : "; for(auto &p:st){ if(p.first==-TINF || p.second==TINF)continue; cout<<"["< struct RangeSet2D{ struct Node; using NP=shared_ptr; using IV=vc>; struct Node{ T l,r,sum; ull pri,h1,h2; int cnt; NP lc,rc; Node(T l,T r,ull pri,NP lc,NP rc,T sum,int cnt,ull h1,ull h2):l(l),r(r),sum(sum),pri(pri),h1(h1),h2(h2),cnt(cnt),lc(lc),rc(rc){} }; struct HSeg{T x1,y,x2;}; struct VSeg{T x,y1,y2;}; struct Reflex{T x,y;int miss;}; static ull mix(ull x){ x+=0x9e3779b97f4a7c15ULL; x=(x^(x>>30))*0xbf58476d1ce4e5b9ULL; x=(x^(x>>27))*0x94d049bb133111ebULL; return x^(x>>31); } struct PairHash{ size_t operator()(const pair &p)const{ ull a=(ull)hash{}(p.first),b=(ull)hash{}(p.second); return (size_t)mix(a^mix(b+0x9e3779b97f4a7c15ULL)); } }; map mp; T TINF; RangeSet2D(){ TINF=numeric_limits::max()/2; mp.emplace(-TINF,NP()); mp.emplace(TINF,NP()); } static T ysum(const NP &p){return p?p->sum:T(0);} static int ycnt(const NP &p){return p?p->cnt:0;} static ull yh1(const NP &p){return p?p->h1:0x243f6a8885a308d3ULL;} static ull yh2(const NP &p){return p?p->h2:0x13198a2e03707344ULL;} static ull priority(T x){ return mix((ull)hash{}(x)+0x9e3779b97f4a7c15ULL); } static bool higher(const NP &a,const NP &b){ if(a->pri!=b->pri)return a->pri>b->pri; return a->l>b->l; } static NP make_node(T l,T r,const NP &lc=NP(),const NP &rc=NP()){ ull p=priority(l); T s=ysum(lc)+(r-l+1)+ysum(rc); int c=ycnt(lc)+1+ycnt(rc); ull z1=mix((ull)hash{}(l)^mix((ull)hash{}(r)+0x243f6a8885a308d3ULL)); ull z2=mix((ull)hash{}(l)+0x13198a2e03707344ULL)^mix((ull)hash{}(r)); ull h1=mix(yh1(lc)^z1^mix(yh1(rc)+0xa4093822299f31d0ULL)); ull h2=mix(yh2(lc)+z2+mix(yh2(rc)^0x082efa98ec4e6c89ULL)); return make_shared(l,r,p,lc,rc,s,c,h1,h2); } static pair ysplit(const NP &p,T key){ if(!p)return {}; if(p->lrc,key); return {make_node(p->l,p->r,p->lc,a),b}; }else{ auto [a,b]=ysplit(p->lc,key); return {a,make_node(p->l,p->r,b,p->rc)}; } } static NP ymerge(const NP &a,const NP &b){ if(!a)return b; if(!b)return a; if(higher(a,b))return make_node(a->l,a->r,a->lc,ymerge(a->rc,b)); return make_node(b->l,b->r,ymerge(a,b->lc),b->rc); } static const Node* yprev(const NP &p,T x){ const Node *ans=nullptr; auto cur=p; while(cur){ if(cur->l<=x){ans=cur.get();cur=cur->rc;} else cur=cur->lc; } return ans; } static const Node* ylower(const NP &p,T x){ const Node *ans=nullptr; auto cur=p; while(cur){ if(cur->l>=x){ans=cur.get();cur=cur->lc;} else cur=cur->rc; } return ans; } static const Node* yfirst(const NP &p){ if(!p)return nullptr; auto cur=p; while(cur->lc)cur=cur->lc; return cur.get(); } static const Node* ylast(const NP &p){ if(!p)return nullptr; auto cur=p; while(cur->rc)cur=cur->rc; return cur.get(); } static bool yequal_exact(const NP &a,const NP &b){ if(a.get()==b.get())return true; if(!a || !b)return false; if(a->l!=b->l || a->r!=b->r)return false; return yequal_exact(a->lc,b->lc) && yequal_exact(a->rc,b->rc); } static bool yequal(const NP &a,const NP &b){ if(a.get()==b.get())return true; if(!a || !b)return false; if(a->cnt!=b->cnt || a->sum!=b->sum || a->h1!=b->h1 || a->h2!=b->h2)return false; return yequal_exact(a,b); } static bool ycovered(const NP &p,T l,T r){ assert(l<=r); auto z=yprev(p,l); return z && z->l<=l && r<=z->r; } static T ymex(const NP &p,T x){ auto z=yprev(p,x); if(z && z->l<=x && x<=z->r)return z->r+1; return x; } static pair yinsert(const NP &root,T l,T r){ assert(l<=r); auto pre=yprev(root,l); if(pre && pre->l<=l && r<=pre->r)return {root,T(0)}; T cut=l; if(pre && pre->r+1>=l)cut=pre->l; auto [a,b]=ysplit(root,cut); auto [m,c]=ysplit(b,r+2); T nl=l,nr=r; if(m){ nl=min(nl,yfirst(m)->l); nr=max(nr,ylast(m)->r); } T d=nr-nl+1-ysum(m); auto z=make_node(nl,nr); return {ymerge(a,ymerge(z,c)),d}; } static pair yerase(const NP &root,T l,T r){ assert(l<=r); auto pre=yprev(root,l); bool hit=pre && pre->r>=l; if(!hit){ auto nx=ylower(root,l); if(!nx || nx->l>r)return {root,T(0)}; } T cut=hit?pre->l:l; auto [a,b]=ysplit(root,cut); auto [m,c]=ysplit(b,r+1); if(!m)return {root,T(0)}; auto f=yfirst(m); auto z=ylast(m); NP mid; T keep=T(0); if(f->ll,l-1)); keep+=l-f->l; } if(rr){ mid=ymerge(mid,make_node(r+1,z->r)); keep+=z->r-r; } T d=ysum(m)-keep; return {ymerge(a,ymerge(mid,c)),d}; } static void yintervals(const NP &root,IV &v){ vc st; auto cur=root; while(cur || !st.empty()){ while(cur){st.pb(cur);cur=cur->lc;} cur=st.back();st.pop_back(); v.pb({cur->l,cur->r}); cur=cur->rc; } } typename map::iterator split(T x){ auto ite=mp.lower_bound(x); if(ite!=mp.end() && ite->first==x)return ite; assert(ite!=mp.begin()); return mp.emplace_hint(ite,x,prev(ite)->second); } void merge(T l,T r){ auto ite=mp.lower_bound(l); if(ite!=mp.begin())ite=prev(ite); while(ite!=mp.end()){ auto nxt=next(ite); if(nxt==mp.end() || nxt->first>r)break; if(nxt->first!=TINF && yequal(ite->second,nxt->second))mp.erase(nxt); else ite=nxt; } } bool covered(T r1,T c1,T r2,T c2)const{ assert(r1<=r2 && c1<=c2); assert(-TINFsecond,c1,c2))return false; auto nxt=next(ite); if(nxt==mp.end() || nxt->first>r2)break; ite=nxt; } return true; } bool covered(T r,T c)const{return covered(r,c,r,c);} T insert(T r1,T c1,T r2,T c2){ assert(r1<=r2 && c1<=c2); assert(-TINF memo; T ret=T(0); for(auto ite=itl;ite!=itr;++ite){ const Node *key=ite->second.get(); auto f=memo.find(key); if(f==memo.end()){ auto [nr,d]=yinsert(ite->second,c1,c2); f=memo.emplace(key,U{nr,d}).first; } auto nxt=next(ite); ret+=(nxt->first-ite->first)*f->second.d; ite->second=f->second.root; } merge(r1,r2+1); return ret; } T insert(T r,T c){return insert(r,c,r,c);} T erase(T r1,T c1,T r2,T c2){ assert(r1<=r2 && c1<=c2); assert(-TINF memo; T ret=T(0); for(auto ite=itl;ite!=itr;++ite){ const Node *key=ite->second.get(); auto f=memo.find(key); if(f==memo.end()){ auto [nr,d]=yerase(ite->second,c1,c2); f=memo.emplace(key,U{nr,d}).first; } auto nxt=next(ite); ret+=(nxt->first-ite->first)*f->second.d; ite->second=f->second.root; } merge(r1,r2+1); return ret; } T erase(T r,T c){return erase(r,c,r,c);} T mex_y(T r,T c=0)const{ assert(-TINFsecond,c); } T mex_x(T c,T r=0)const{ assert(-TINFsecond,c,c)){ auto nxt=next(ite); r=nxt->first; ite=nxt; } return r; } ll size()const{ ll ret=0; for(auto ite=mp.begin();next(ite)!=mp.end();++ite)ret+=ycnt(ite->second); return ret; } static bool iv_covered(const IV &v,T l,T r){ if(l>r)return true; int lo=0,hi=(int)v.size(); while(lo intersect_iv(const shared_ptr &a,const shared_ptr &b,const shared_ptr &empty){ if(a.get()==b.get())return a; if(a->empty() || b->empty())return empty; auto c=make_shared(); int i=0,j=0; while(i<(int)a->size() && j<(int)b->size()){ T l=max((*a)[i].first,(*b)[j].first); T r=min((*a)[i].second,(*b)[j].second); if(l<=r)c->pb({l,r}); if((*a)[i].second<(*b)[j].second)i++; else j++; } if(c->empty())return empty; return c; } vc> rectangles()const{ vc> nodes; for(auto ite=next(mp.begin());ite!=mp.end() && ite->first!=TINF;++ite)nodes.pb(*ite); if(nodes.size()<2)return {}; unordered_map> cache; auto empty=make_shared(); auto get_iv=[&](const NP &p)->shared_ptr{ if(!p)return empty; auto f=cache.find(p.get()); if(f!=cache.end())return f->second; auto v=make_shared(); v->reserve(ycnt(p)); yintervals(p,*v); cache[p.get()]=v; return v; }; int nx=(int)nodes.size()-1; vc xs(nodes.size()); vc> siv(nodes.size()); rep(i,0,(ll)nodes.size()){ xs[i]=nodes[i].first; siv[i]=get_iv(nodes[i].second); } vc hbound; vc vbound; vc rv; rep(i,0,nx){ T x1=xs[i],x2=xs[i+1]; for(auto [l,r]:*siv[i]){ hbound.pb({x1,l,x2}); hbound.pb({x1,r+1,x2}); } } auto transition=[&](T x,const IV &a,const IV &b){ vc ea,eb; ea.reserve(a.size()*2); eb.reserve(b.size()*2); for(auto [l,r]:a){ea.pb(l);ea.pb(r+1);} for(auto [l,r]:b){eb.pb(l);eb.pb(r+1);} int i=0,j=0; bool sa=false,sb=false,has=false; T pre=T(); while(i<(int)ea.size() || j<(int)eb.size()){ T y; if(j==(int)eb.size() || (i<(int)ea.size() && ea[i]> seg(segN*2,empty); rep(i,0,nx)seg[segN+i]=siv[i]; for(int i=segN-1;i;i--)seg[i]=intersect_iv(seg[i<<1],seg[i<<1|1],empty); auto range_covered=[&](int l,int r,T a,T b)->bool{ l+=segN; r+=segN; while(l>=1; r>>=1; } return true; }; int R=(int)rv.size(); vc ord(R); iota(nall(ord),0); vc hc; vc vcand; sort(nall(ord),[&](int a,int b){ if(rv[a].y!=rv[b].y)return rv[a].y> g(H); struct Ev{T x;int tp,id;}; vc ev; ev.reserve(H*2+V); rep(i,0,H){ev.pb({hc[i].x1,0,(int)i});ev.pb({hc[i].x2,2,(int)i});} rep(i,0,V)ev.pb({vcand[i].x,1,(int)i}); sort(nall(ev),[](const Ev &a,const Ev &b){ if(a.x!=b.x)return a.x> active; for(auto e:ev){ if(e.tp==0)active.emplace(hc[e.id].y,e.id); else if(e.tp==2)active.erase({hc[e.id].y,e.id}); else{ auto &v=vcand[e.id]; auto ite=active.lower_bound({v.y1,numeric_limits::min()}); while(ite!=active.end() && ite->first<=v.y2){ g[ite->second].pb(e.id); ++ite; } } } vc ml(H,-1),mr(V,-1),dist(H); auto bfs=[&]()->bool{ queue q; fill(nall(dist),-1); rep(i,0,H)if(ml[i]==-1){dist[i]=0;q.push(i);} bool ok=false; while(!q.empty()){ int u=q.front();q.pop(); for(int v:g[u]){ int w=mr[v]; if(w==-1)ok=true; else if(dist[w]==-1){dist[w]=dist[u]+1;q.push(w);} } } return ok; }; auto dfs=[&](auto &&self,int u)->bool{ for(int v:g[u]){ int w=mr[v]; if(w==-1 || (dist[w]==dist[u]+1 && self(self,w))){ ml[u]=v; mr[v]=u; return true; } } dist[u]=-1; return false; }; while(bfs())rep(i,0,H)if(ml[i]==-1)dfs(dfs,i); vc zh(H),zv(V); queue> q; rep(i,0,H)if(ml[i]==-1){zh[i]=1;q.emplace(0,i);} while(!q.empty()){ auto [s,u]=q.front();q.pop(); if(s==0){ for(int v:g[u]){ if(ml[u]==v || zv[v])continue; zv[v]=1; q.emplace(1,v); } }else if(mr[u]!=-1 && !zh[mr[u]]){ zh[mr[u]]=1; q.emplace(0,mr[u]); } } vc selh; vc selv; unordered_set,PairHash> used; rep(i,0,H)if(zh[i]){ selh.pb(hc[i]); used.emplace(hc[i].x1,hc[i].y); used.emplace(hc[i].x2,hc[i].y); } rep(i,0,V)if(!zv[i]){ selv.pb(vcand[i]); used.emplace(vcand[i].x,vcand[i].y1); used.emplace(vcand[i].x,vcand[i].y2); } vc rem; rep(i,0,R)if(!used.contains({rv[i].x,rv[i].y}))rem.pb(i); vc ext; vc barriers=vbound; for(auto z:selv)barriers.pb(z); if(!rem.empty()){ vc ys; ys.reserve(rem.size()); for(int i:rem)ys.pb(rv[i].y); sort(nall(ys)); ys.erase(unique(nall(ys)),ys.end()); int sn=1; while(sn<(int)ys.size())sn<<=1; vc mx(sn*2,-TINF),mn(sn*2,TINF); auto updmax=[&](int l,int r,T x){ for(l+=sn,r+=sn;l>=1,r>>=1){ if(l&1)mx[l]=max(mx[l],x),l++; if(r&1)--r,mx[r]=max(mx[r],x); } }; auto updmin=[&](int l,int r,T x){ for(l+=sn,r+=sn;l>=1,r>>=1){ if(l&1)mn[l]=min(mn[l],x),l++; if(r&1)--r,mn[r]=min(mn[r],x); } }; auto getmax=[&](int p){ T ret=-TINF; for(p+=sn;p;p>>=1)ret=max(ret,mx[p]); return ret; }; auto getmin=[&](int p){ T ret=TINF; for(p+=sn;p;p>>=1)ret=min(ret,mn[p]); return ret; }; vc bo(barriers.size()),qo=rem; iota(nall(bo),0); sort(nall(bo),[&](int a,int b){return barriers[a].x lans(R,-TINF),rans(R,TINF); int p=0; for(int id:qo){ while(p<(int)bo.size() && barriers[bo[p]].xbarriers[b].x;}); sort(nall(qo),[&](int a,int b){return rv[a].x>rv[b].x;}); p=0; for(int id:qo){ while(p<(int)bo.size() && barriers[bo[p]].x>rv[id].x){ auto z=barriers[bo[p++]]; int l=lower_bound(nall(ys),z.y1)-ys.begin(); int r=upper_bound(nall(ys),z.y2)-ys.begin(); if(l hs=hbound; hs.insert(hs.end(),nall(selh)); hs.insert(hs.end(),nall(ext)); vc vs=vbound; vs.insert(vs.end(),nall(selv)); auto merge_h=[&](vc a){ sort(nall(a),[](const HSeg &p,const HSeg &q){ if(p.y!=q.y)return p.y b; for(auto z:a){ if(z.x1==z.x2)continue; if(b.empty() || b.back().y!=z.y || b.back().x2 a){ sort(nall(a),[](const VSeg &p,const VSeg &q){ if(p.x!=q.x)return p.x b; for(auto z:a){ if(z.y1==z.y2)continue; if(b.empty() || b.back().x!=z.x || b.back().y2> hp(hs.size()),vp(vs.size()); rep(i,0,(ll)hs.size()){hp[i].pb(hs[i].x1);hp[i].pb(hs[i].x2);} rep(i,0,(ll)vs.size()){vp[i].pb(vs[i].y1);vp[i].pb(vs[i].y2);} vc ev2; ev2.reserve(hs.size()*2+vs.size()); rep(i,0,(ll)hs.size()){ev2.pb({hs[i].x1,0,(int)i});ev2.pb({hs[i].x2,2,(int)i});} rep(i,0,(ll)vs.size())ev2.pb({vs[i].x,1,(int)i}); sort(nall(ev2),[](const Ev &a,const Ev &b){ if(a.x!=b.x)return a.x::min()}); while(ite!=active.end() && ite->first<=z.y2){ hp[ite->second].pb(z.x); vp[e.id].pb(ite->first); ++ite; } } } using Point=pair; vc> edges; rep(i,0,(ll)hs.size()){ auto &v=hp[i]; sort(nall(v)); v.erase(unique(nall(v)),v.end()); rep(j,1,(ll)v.size())if(v[j-1] pid; vc pt; vc> adj; auto gid=[&](Point p){ auto f=pid.find(p); if(f!=pid.end())return f->second; int id=pt.size(); pid[p]=id; pt.pb(p); adj.pb({-1,-1,-1,-1}); return id; }; auto dir=[&](Point a,Point b){ if(b.firsta.second)return 1; if(b.first>a.first)return 2; return 3; }; for(auto [a,b]:edges){ int u=gid(a),v=gid(b); int d=dir(a,b); adj[u][d]=v; adj[v][(d+2)%4]=u; } vc> seen(pt.size()); vc> ret; rep(s,0,(ll)pt.size())rep(sd,0,4){ if(adj[s][sd]==-1 || seen[s][sd])continue; int u=s,d=sd; T lx=pt[u].first,rx=pt[u].first,ly=pt[u].second,ry=pt[u].second; int firstv=adj[u][d]; T sr,sc; if(d==0){sr=pt[firstv].first;sc=pt[u].second;} else if(d==1){sr=pt[u].first;sc=pt[u].second;} else if(d==2){sr=pt[u].first;sc=pt[u].second-1;} else{sr=pt[u].first-1;sc=pt[firstv].second;} while(true){ seen[u][d]=1; int v=adj[u][d]; lx=min(lx,pt[v].first);rx=max(rx,pt[v].first); ly=min(ly,pt[v].second);ry=max(ry,pt[v].second); int nd=-1; int cand[4]={(d+1)%4,d,(d+3)%4,(d+2)%4}; for(int z:cand)if(adj[v][z]!=-1){nd=z;break;} assert(nd!=-1); u=v;d=nd; if(u==s && d==sd)break; } bool inside=false; if(-TINFfirst==-TINF || nxt->first==TINF)continue; IV v; v.reserve(ycnt(ite->second)); yintervals(ite->second,v); for(auto [l,r]:v)cout<<"["<first<<", "<first-1<<"]x["<> h >> w >> n; RangeSet2D st; rep(i,0,n){ ll r1,c1,r2,c2; cin >> r1 >> c1 >> r2 >> c2; st.insert(r1,r2,c1,c2); } auto rect=st.rectangles(); //st.output(); ll sum=0; for(auto [r1,c1,r2,c2]:rect)sum+=(r2-r1+1)*(c2-c1+1); cout << h*w-sum << endl; }