E - 秋实大哥与家
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
Submit Status
秋实大哥是一个顾家的男人,他认为人生就是旅途,不管我们漂到哪,最终还是会回到温暖的地方——家。
所以他买了很多家具。
秋实大哥的家可以看成一个W×H的矩阵,每一件家具可以看成一个矩形,他们放置在秋实大哥的家里,相互之间没有重叠。
现在秋实大哥购置了一个新的大小为1×M的家具,秋实大哥想知道他有多少种方式来安放这个家具。
Input
第一行包含四个整数W,H,n,M,表示秋实大哥家的大小为W×H,现在已有n个家具,新购置的家具大小为1×M。
接下来n行,每行包含4个整数x1,y1,x2,y2,分别表示这个家具左下角的坐标和右上角的坐标。
1≤n,H,W,M≤100000,1≤x1≤x2≤W,1≤y1≤y2≤H。
Output
输出一行包含一个整数,表示有多少种方案可以来放置秋实大哥的新家具,要求不能跟原有的家具重叠,也不能超出家的范围。
Sample input and output
Sample Input | Sample Output |
---|---|
3 3 1 2 2 2 2 2 | 8 |
解题报告:
注意到所有的家具是1 x m的,不外乎横放与竖放,我们先考虑横放,对于每个矩形,其左端线坐标为x1,右端线坐标为x2.
那么下列这些点肯定无法放置的(以这些点为最左端放置)
(X1-m+1,x2) , y ∈ [y1,y2]
那么问题就好解决了,每读入一个矩形,将其线延长,之后算不合法的面积,用总面积减去不合法的面积即为方案数.
竖放的道理一样,这里不再阐述.注意到 m = 1的情况,横 / 竖是一样的
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <cstdio> 5 typedef long long ll; 6 using namespace std; 7 const int maxn = 6e5 + 50; 8 const int maxtreesize = 6e5 + 50; 9 int w,h,n,m,size=0; 10 11 typedef struct node 12 { 13 int l,r,cover,sum; 14 }; 15 16 node tree[maxtreesize]; 17 18 void push_up(int cur) 19 { 20 int lc = 2*cur; 21 int rc = 2*cur+1; 22 if (tree[cur].cover) 23 tree[cur].sum = tree[cur].r - tree[cur].l; 24 else if(tree[cur].l == tree[cur].r ) // 叶子 25 tree[cur].sum = 0; 26 else 27 { 28 if (tree[lc].cover && tree[rc].cover ) // Updata Father 29 tree[cur].sum = tree[lc].sum + tree[rc].sum; 30 else 31 tree[cur].sum = tree[lc].sum + tree[rc].sum; 32 } 33 34 } 35 36 37 void updata(int ql,int qr,int v,int cur) 38 { 39 int lc = 2*cur , rc = 2*cur + 1 , l = tree[cur].l , r = tree[cur].r; 40 if (r == l) // 元 41 return; 42 if (l >= ql && r <= qr) 43 { 44 tree[cur].cover += v; 45 push_up(cur); 46 } 47 else 48 { 49 int mid = l + (r-l)/2; 50 if (mid > ql) 51 updata(ql,qr,v,lc); 52 if (mid < qr) 53 updata(ql,qr,v,rc); 54 push_up(cur); 55 } 56 } 57 58 void build_tree(int cur,int l,int r) 59 { 60 tree[cur].l = l,tree[cur].r = r; 61 if (r - l > 1 ) 62 { 63 int mid = l + (r-l)/2; 64 build_tree(2*cur,l,mid); 65 build_tree(2*cur+1,mid,r); 66 } 67 } 68 69 70 typedef struct line 71 { 72 int x1,x2,y1,y2; 73 bool flag; // 0 是入边,1 是出边 74 inline int getx() 75 { 76 if (flag) 77 return x2; 78 else 79 return x1; 80 } 81 inline int gety() 82 { 83 if (flag) 84 return y2; 85 else 86 return y1; 87 } 88 }; 89 90 line a[maxn]; // x 方向上被限制 91 line b[maxn]; // y 方向上被限制 92 93 bool cmp1(line a,line b) 94 { 95 return a.getx() < b.getx(); 96 } 97 98 bool cmp2(line a,line b) 99 { 100 return a.gety() < b.gety(); 101 } 102 103 void dump__() 104 { 105 for(int i = 0 ; i < size ; ++ i) 106 { 107 if (a[i].flag == 0) 108 { 109 printf("入边 , x is %d , y1 is %d, y2 is %d\n",a[i].getx(),a[i].y1 , a[i].y2); 110 } 111 else 112 printf("出边 , x is %d , y1 is %d, y2 is %d\n",a[i].getx(),a[i].y1 , a[i].y2); 113 } 114 } 115 116 void dump() 117 { 118 for(int i = 0 ; i < size ; ++ i) 119 { 120 if (b[i].flag == 0) 121 { 122 printf("入边 , y is %d ,left is %d,right is %d\n",b[i].y1,b[i].x1,b[i].x2 ); 123 } 124 else 125 { 126 printf("出边 , y is %d ,left is %d,right is %d\n",b[i].y2,b[i].x1,b[i].x2 ); 127 } 128 } 129 } 130 131 ll sall; //总面积 132 133 134 ll slove1() 135 { 136 ll res = 0; 137 sort(a,a+size,cmp1); 138 int cur = 1; 139 updata(a[0].y1,a[0].y2,1,1); 140 while(cur < size) 141 { 142 int dis = a[cur].getx() - a[cur-1].getx(); 143 res += (ll)dis*(ll)tree[1].sum; 144 if (a[cur].flag & 1) //出边 145 updata(a[cur].y1,a[cur].y2,-1,1); 146 else 147 updata(a[cur].y1,a[cur].y2,1,1); 148 cur++; 149 } 150 return sall - res; 151 } 152 153 154 ll slove2() 155 { 156 ll res = 0; 157 sort(b,b+size,cmp2); 158 int cur = 1; 159 updata(b[0].x1,b[0].x2,1,1); 160 while(cur < size) 161 { 162 int dis = b[cur].gety() - b[cur-1].gety(); 163 res += (ll)dis*(ll)tree[1].sum; 164 if (b[cur].flag & 1) //出边 165 updata(b[cur].x1,b[cur].x2,-1,1); 166 else 167 updata(b[cur].x1,b[cur].x2,1,1); 168 cur++; 169 } 170 return sall - res; 171 } 172 173 int main(int argc,char *argv[]) 174 { 175 scanf("%d%d%d%d",&w,&h,&n,&m); 176 memset(tree,0,sizeof(tree)); 177 memset(a,0,sizeof(a)); 178 memset(b,0,sizeof(b)); 179 build_tree(1,0,max(w,h)+4); // Build Tree 180 sall = (ll)w*(ll)h; 181 for(int i = 0 ; i < n ; ++ i) 182 { 183 int x1,y1,x2,y2,oriy1,orix1; 184 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 185 x1 -- , y1 -- ; //转换为线段式 186 orix1 = x1,oriy1 = y1; 187 x1 = x1-m+1 >= 0 ? x1-m+1 : 0; 188 y1 = y1-m+1 >= 0 ? y1-m+1 : 0; 189 a[size].x1 = x1,a[size].x2 = x2,a[size].y1 = oriy1 , a[size].y2 = y2 , a[size].flag = 0; 190 b[size].x1 = orix1 , b[size].x2 = x2 , b[size].y1 = y1,b[size].y2 = y2 , b[size++].flag = 0; 191 a[size].x1 = x1,a[size].x2 = x2,a[size].y1 = oriy1 , a[size].y2 = y2 , a[size].flag = 1; 192 b[size].x1 = orix1 , b[size].x2 = x2 , b[size].y1 = y1,b[size].y2 = y2 , b[size++].flag = 1; 193 } 194 ll ans = 0; 195 a[size].x1 = w-m + 1 >= 0 ? w-m+1 : 0 , a[size].x2 = w , a[size].y1 = 0 , a[size].y2 = h,a[size++].flag = 0; //添加限制线 196 a[size].x1 = w-m + 1 >= 0 ? w-m+1 : 0 , a[size].x2 = w , a[size].y1 = 0 , a[size].y2 = h,a[size++].flag = 1; 197 ans += slove1(); 198 size -= 2; 199 b[size].x1 = 0,b[size].x2 = w ,b[size].y1 = h-m+1 >= 0 ? h-m+1 : 0,b[size].y2 = h , b[size++].flag = 0; 200 b[size].x1 = 0,b[size].x2 = w ,b[size].y1 = h-m+1 >= 0 ? h-m+1 : 0,b[size].y2 = h , b[size++].flag = 1; 201 ans += slove2(); 202 if (m == 1) 203 printf("%lld\n",ans/2); 204 else 205 printf("%lld\n",ans); 206 return 0; 207 }