比較老的題。給一個矩形和一些已經覆蓋了的小矩形,問在剩餘的空格上放一個長爲m的條有多少种放法。
可以用線段樹化爲矩形面積並搞。這裏練習一下平衡樹的做法,set也比較短。
把矩形變爲入和出兩個事件,根據這些事件計算某行有多少空格,就能計算橫着放有多少种放法。然後橫豎各做一遍。
這裏利用set可以找到插入線段的兩端第一個非空位置。
注意幾個地方:
1.long long
2.m爲1的情況,橫豎是一樣的。
3.排序事件時,要先出後進。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<algorithm>
using namespace std;
#define NN 50100
int m;
set<int> st;
struct rect{
int sx,sy,ex,ey;
}r[NN];
struct node{
int sx,ex,t,tag;
void init(int a,int b,int c,int d){
sx=a;ex=b;t=c;tag=d;
}
}ev[NN*2],nd;
bool cmp(node x,node y){
if (x.t==y.t) return x.tag<y.tag;
else return x.t<y.t;
}
int initeven1(int n,int w,int h){
int i;
int ret=0;
for(i=1;i<=n;++i){
nd.init(r[i].sy,r[i].ey,r[i].sx,1);
ev[++ret]=nd;
nd.init(r[i].sy,r[i].ey,r[i].ex+1,-1);
if (nd.t<=w) ev[++ret]=nd;
}
nd.init(0,h+1,1,1);
ev[0]=nd;
nd.init(0,h+1,w+1,-1);
ev[ret+1]=nd;
sort(ev+1,ev+ret+1,cmp);
return ret;
}
int initeven2(int n,int w,int h){
int i;
int ret=0;
for(i=1;i<=n;++i){
nd.init(r[i].sx,r[i].ex,r[i].sy,1);
ev[++ret]=nd;
nd.init(r[i].sx,r[i].ex,r[i].ey+1,-1);
if (nd.t<=w) ev[++ret]=nd;
}
nd.init(0,h+1,1,1);
ev[0]=nd;
nd.init(0,h+1,w+1,-1);
ev[ret+1]=nd;
sort(ev+1,ev+ret+1,cmp);
return ret;
}
int insert(node ev){
int ret=0;
set<int>::iterator it;
set<int>::iterator rit;
int ll,rr,tmp;
if (ev.tag<0){
it=st.find(ev.ex);
rit=st.find(ev.sx);
it++;
rit--;
ll=*rit;
rr=*it;
tmp=ev.sx-1-ll;
if (tmp>=m) ret-=tmp+1-m;
tmp=rr-1-ev.ex;
if (tmp>=m) ret-=tmp+1-m;
tmp=rr-1-ll;
if (tmp>=m) ret+=tmp+1-m;
st.erase(ev.sx);
st.erase(ev.ex);
}
else{
st.insert(ev.sx);
st.insert(ev.ex);
it=st.find(ev.ex);
rit=st.find(ev.sx);
it++;
rit--;
ll=*rit;
rr=*it;
tmp=ev.sx-1-ll;
if (tmp>=m) ret+=tmp+1-m;
tmp=rr-1-ev.ex;
if (tmp>=m) ret+=tmp+1-m;
tmp=rr-1-ll;
if (tmp>=m) ret-=tmp+1-m;
}
return ret;
}
long long work(int n,int tn,int w,int h){
int i;
int t,tlen;
long long sum=0,ret=0;
st.clear();
insert(ev[0]);
if (h>=m){
sum=h+1-m;
}
ret+=sum*(ev[1].t-1);
for(i=1;i<=tn;){
t=ev[i].t;
while(ev[i].t==t){
sum+=insert(ev[i]);
++i;
}
tlen=ev[i].t-t;
ret+=sum*tlen;
}
return ret;
}
int n,w,h;
int main(){
//freopen("bin.txt","r",stdin);
int i,tn;
long long ans1,ans2=0;
while(scanf("%d%d%d%d",&w,&h,&n,&m)!=EOF){
for(i=1;i<=n;++i){
scanf("%d%d%d%d",&r[i].sx,&r[i].sy,&r[i].ex,&r[i].ey);
}
tn=initeven1(n,w,h);
ans1=work(n,tn,w,h);
if (m>1){
tn=initeven2(n,h,w);
ans2=work(n,tn,h,w);
}
else ans2=0;
printf("%I64d\n",ans1+ans2);
}
return 0;
}