1 /*
  2 题意:给你n*m的棋盘,有些棋盘被一些矩形覆盖,求放进一个长为M,宽为1的矩形的方案数
  3 
  4 离散,线段树 +扫描线 
  5 分析:最直接得想法,对于每一层统计空白连续的长度然后统计放的方案数,不过编程复杂度有点高
  6 要分别记录下每个区间左边连续最长空白长度和右边最长连续空白长度,
  7 然后count[rt]=count[r<<1]+count[rt<<1|1]+{跨两段的个数} 
  8 
  9 一个好想法:当以y为分层标准时,统计竖着放的方案数,那么把每个矩形都向下延伸M-1个单位,
 10 那么剩下的每一个空位都对应一种方法,直接矩形并求面积就好,问题得到转化;
 11 
 12 一些细节:扫描线的细节处非常有意思;
 13 首先题目给我们的数据是对应一段区间的,比如矩形[2,2,2,2]表示长宽都为1的矩形,为了方便,我们把它转化成
 14 [1,1,2,2]这样在统计的时候直接相减就可以了, 
 15 */
 16 #include<cstdio>
 17 #include<cstring>
 18 #include<cstdlib>
 19 #include<iostream>
 20 #include<algorithm>
 21 #include<cmath>
 22 #include<vector>
 23 #include<set>
 24 #define lson l,m,rt<<1
 25 #define rson m+1,r,rt<<1|1
 26 #define Find(i) lower_bound(LX.begin(),LX.begin()+n1,i)-LX.begin()
 27 using namespace std;
 28 const int NN=100000+10;
 29 typedef long long LL;
 30 struct Edge{
 31     int hi,ls,rs,s;
 32     Edge(){}
 33     Edge(int a,int b,int c,int e):hi(a),ls(b),rs(c),s(e){}
 34     bool operator < (const Edge &p)const{
 35         return hi<p.hi;
 36     }
 37 }; 
 38 vector<Edge> E;
 39 vector<int> LX;
 40 int len[NN<<2],cov[NN<<2];
 41 int W,H,N,M,n1;
 42 int x[NN/2],y[NN/2],x2[NN/2],y2[NN/2];
 43 LL ans;
 44 void pushup(int l,int r,int rt){
 45     if (cov[rt]>=1){
 46         len[rt]=(LX[r+1]-LX[l]);
 47     }else if (l==r) len[rt]=0;
 48     else len[rt]=len[rt<<1]+len[rt<<1|1]; 
 49 }
 50 void update(int L,int R,int v,int l,int r,int rt){
 51     if (L<=l && r<=R){
 52         cov[rt]+=v;
 53         if (cov[rt]>=1) len[rt]=(LX[r+1]-LX[l]);
 54         else if (l==r) len[rt]=0;
 55         else len[rt]=len[rt<<1]+len[rt<<1|1];
 56         return ;
 57     }
 58     int m=(l+r)>>1;
 59     if (L<=m) update(L,R,v,lson);
 60     if (m< R) update(L,R,v,rson);
 61     pushup(l,r,rt);
 62 }
 63 
 64 void work(){
 65     E.clear();LX.clear();
 66     E.push_back(Edge(max(0,H-M+1),0,W,1));
 67     E.push_back(Edge(H,0,W,-1));
 68     LX.push_back(0);LX.push_back(W);//最后面要加入一个大矩形    
 69     for (int i=0;i<N;i++){
 70         E.push_back(Edge(max(0,y[i]-M),x[i]-1,x2[i],1));//矩形往下延伸 
 71         E.push_back(Edge(y2[i],x[i]-1,x2[i],-1));
 72         LX.push_back(x[i]-1);LX.push_back(x2[i]);
 73 
 74     }
 75     sort(E.begin(),E.end());
 76     sort(LX.begin(),LX.end());
 77     n1=unique(LX.begin(),LX.end())-LX.begin();
 78     
 79     LL ret=0;
 80     memset(len,0,sizeof(len));
 81     memset(cov,0,sizeof(cov));
 82 //    cout<<"**** "<<endl;
 83     for (int i=0;i<E.size();i++){
 84     //    cout<<E[i].hi<<" "<<E[i].ls<<" "<<E[i].rs<<" "<<E[i].s<<endl;
 85         int l=Find(E[i].ls),r=Find(E[i].rs)-1;
 86         if (l<=r) update(l,r,E[i].s,0,n1-1,1);
 87         if (E[i].hi!=E[i+1].hi){
 88         //    cout<<len[1]<<endl;
 89             ret+=(LL)len[1]*(E[i+1].hi-E[i].hi);
 90         }
 91     }
 92     ans+=(LL)W*H-ret;
 93 }
 94 int main(){
 95     while (~scanf("%d%d%d%d",&W,&H,&N,&M)){
 96         for (int i=0;i<N;i++){
 97             scanf("%d%d%d%d",x+i,y+i,x2+i,y2+i);
 98         }
 99         ans=0;
100         work();
101         if (M!=1) {
102             swap(H,W);
103             for (int i=0;i<N;i++){
104                 swap(x[i],y[i]);swap(x2[i],y2[i]);
105             }
106             work();
107         }
108         printf("%lld\n",ans);
109     }
110 }

优质内容筛选与推荐>>
1、一种在没有软驱、硬盘为 SCSI/STAT接口的系统中安装 Windows XP的方法
2、Sql Server 开放4399端口命令行
3、链表练习题
4、ABP递归生成无限级菜单
5、吴裕雄--天生自然 JAVASCRIPT开发学习: 闭包


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号