Kalevich Strikes Back(扫描线求分块的面积)
2014-08-10 14:03
344 查看
http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=216#problem/W
大致题意:有一个W*H的矩形,它的左下角是(0,0),右上角是(W,H),在这个大的矩形内有n个小矩形,这n个小矩形可以包含但不能相交,n个小矩形把W*H的大矩形分成n+1块,按从小到大的顺序输出每一块面积。
首先先计算出每个矩形的面积,对于每一块的面积,我们只需知道这个矩形所包含的矩形,然后减去它所包含的矩形的面积,就是这一块的面积。我们用线段树维护一段线段上被哪个矩形覆盖,当遍历到一条边时,我们只需查询这条边被覆盖的信息,就知道它的前驱了,它们之间建一条边。
对矩形的横坐标进行离散化,建立一棵线段树,节点增加一个信息col,表示这一段被哪一条线段覆盖。
每个矩形产生两条线段,线段节点增加一个信息tag,标志着这条线段是哪一条线段以及是下边还是上边。对线段按y排序后,从下往上开始扫描,对于当前的线段,在线段树中查找其对应的前驱,即它所在外面矩形的下边,它们之间建一条有向边。
最后dfs分别减去一个矩形内所包含的矩形。
大致题意:有一个W*H的矩形,它的左下角是(0,0),右上角是(W,H),在这个大的矩形内有n个小矩形,这n个小矩形可以包含但不能相交,n个小矩形把W*H的大矩形分成n+1块,按从小到大的顺序输出每一块面积。
首先先计算出每个矩形的面积,对于每一块的面积,我们只需知道这个矩形所包含的矩形,然后减去它所包含的矩形的面积,就是这一块的面积。我们用线段树维护一段线段上被哪个矩形覆盖,当遍历到一条边时,我们只需查询这条边被覆盖的信息,就知道它的前驱了,它们之间建一条边。
对矩形的横坐标进行离散化,建立一棵线段树,节点增加一个信息col,表示这一段被哪一条线段覆盖。
每个矩形产生两条线段,线段节点增加一个信息tag,标志着这条线段是哪一条线段以及是下边还是上边。对线段按y排序后,从下往上开始扫描,对于当前的线段,在线段树中查找其对应的前驱,即它所在外面矩形的下边,它们之间建一条有向边。
最后dfs分别减去一个矩形内所包含的矩形。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <list> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> #define LL long long #define _LL __int64 #define eps 1e-12 #define PI acos(-1.0) #define C 240 #define S 20 using namespace std; const int maxn = 120010; struct node { int l,r; int col; }tree[maxn*4]; struct Line { int x1,x2,y,tag; bool operator < (const struct Line &tmp)const { return y < tmp.y; } }line[maxn]; LL s[60010]; int x[maxn],cnt; int pre[maxn]; vector <int> edge[maxn]; int Binsearch(int l, int r, int key) { int low = l; int high = r; while(high >= low) { int mid = (low + high) >> 1; if(x[mid] == key) return mid; if(x[mid] > key) high = mid-1; else low = mid+1; } return -1; } void push_down(int v) { if(tree[v].l == tree[v].r) return; if(tree[v].col != -1) { tree[v*2].col = tree[v*2+1].col = tree[v].col; tree[v].col = -1; } } void build(int v,int l,int r) { tree[v].l = l; tree[v].r = r; tree[v].col = 0; if(l == r) return; int mid = (l+r)>>1; build(v*2,l,mid); build(v*2+1,mid+1,r); } //询问[l,r]所在区间的被覆盖的是哪条线段,那么这条线段就是当前线段的前驱 int query(int v, int l, int r) { if(tree[v].col != -1) return tree[v].col; int mid = (tree[v].l + tree[v].r) >> 1; if(r <= mid) return query(v*2,l,r); else if(l > mid) return query(v*2+1,l,r); else return query(v*2,l,mid); } void update(int v, int l, int r, int tag) { if(tree[v].l == l && tree[v].r == r) { if(tag > 0) tree[v].col = tag; else tree[v].col = pre[-tag]; //重点理解,这条边是上边,要把对应的区间置为它下边的前驱 return; } push_down(v); int mid = (tree[v].l + tree[v].r) >> 1; if(r <= mid) update(v*2,l,r,tag); else if(l > mid) update(v*2+1,l,r,tag); else { update(v*2,l,mid,tag); update(v*2+1,mid+1,r,tag); } } //根据建立的边减去每个矩形所包含的矩形 void dfs(int u) { for(int i = 0; i < (int)edge[u].size(); i++) { int v = edge[u][i]; s[u] -= s[v]; dfs(v); } } int main() { int n,W,H,x1,x2,y1,y2; scanf("%d %d %d",&n,&W,&H); s[0] = (LL)W*H; cnt = 0; memset(pre,0,sizeof(pre)); for(int i = 1; i <= n; i++) { scanf("%d %d %d %d",&x1,&y1,&x2,&y2); if(x1 > x2) swap(x1,x2); if(y1 > y2) swap(y1,y2); line[++cnt] = (struct Line){x1,x2,y1,i}; x[cnt] = x1; line[++cnt] = (struct Line){x1,x2,y2,-i}; x[cnt] = x2; s[i] = (LL)(x2-x1)*(y2-y1); } sort(x+1,x+1+cnt); int k = 1; for(int i = 2; i <= cnt; i++) { if(x[i] != x[k]) x[++k] = x[i]; } cnt = k; build(1,1,cnt); sort(line+1,line+1+n*2); for(int i = 1; i <= n*2; i++) { int l = Binsearch(1,cnt,line[i].x1); int r = Binsearch(1,cnt,line[i].x2)-1; if(line[i].tag > 0) { pre[line[i].tag] = query(1,l,r); edge[pre[line[i].tag]].push_back(line[i].tag); } update(1,l,r,line[i].tag); } dfs(0); sort(s,s+n+1); for(int i = 0; i <= n; i++) { printf("%lld",s[i]); if(i == n) printf("\n"); else printf(" "); } return 0; }
相关文章推荐
- SGU 319: Kalevich Strikes Back
- sgu-319-Kalevich Strikes Back-线段树
- SGU 319 Kalevich Strikes Back(线段树扫描线)
- SGU 319 Kalevich Strikes Back(线段树扫描线)
- Kalevich Strikes Back
- SGU 319 Kalevich Strikes Back(线段树+扫描线)
- SGU 319 Kalevich Strikes Back(线段树+扫描线)
- SGU 319 Kalevich Strikes Back 线段树维护lazy 建树 + dfs
- [HDU 4419] Colourful Rectangle (扫描线 矩形面积并)
- BZOJ 1845 CQOI 2005 三角形面积并 扫描线
- 线段树求矩形面积并 方法详解 (扫描线)HDU 1542 & HDU 3265 & POJ 1151
- HDU - 1255 覆盖的面积(线段树 + 扫描线)
- hdu 1542 线段树之扫描线之面积并
- HDU1255 覆盖的面积 (扫描线)
- POJ 2482 扫描线(面积覆盖最大次数)
- 【codevs 3044】 矩形面积求并 【线段树 扫描线 离散化】
- HDU 1255 覆盖的面积 (线段树 + 离散化 + 扫描线)
- Codeforces Round #181 (Div. 2) E. Empire Strikes Back N!∣∏K,i=1ai!
- Atlantis 线段树扫描线--面积并
- HDU 1255 覆盖的面积 (扫描线 线段树 离散化 矩形面积并)