原题链接:http://122.207.68.93/OnlineJudge/problem.php?id=1292
线段树+扫描线。这道题是典型的矩形面积并问题,乍一看109 * 109 * 105 超了long long,但这个无关紧要,其实如果总面积>1018 可以直接判断肯定有相交的面积了,这么一来,就是裸模版题了,贴膜板:
1 #include "cstdio" 2 #include "iostream" 3 #include "algorithm" 4 #define lson cur<<1 5 #define rson cur<<1|1 6 using namespace std; 7 typedef long long LL; 8 const int maxn = 200000 + 5; 9 const int root = 1; 10 struct seg //扫描线结构体 11 { 12 int x, y1, y2; //扫描线数据 x横坐标 y1,y2,上下顶点 13 short flag; //标记是进入的还是出来的(对于一个矩形所产生的两条扫描线来说) 14 seg() {}; 15 seg(int a, int b, int c, short d):x(a), y1(b), y2(c), flag(d) {} 16 inline friend bool operator <(seg a, seg b) 17 { 18 return a.x < b.x; //用于sort 19 } 20 } ss[maxn]; 21 int m; //扫描线总数 22 int y[maxn]; //离散值-->实际值 23 struct node //线段树结构体 (加入的是扫描线(纵向)) 24 { 25 int l, r, cover; //左右范围(实际上没有用),cover:是否完全覆盖 26 int yl, yr, len; //实际范围和长度 27 node() {} 28 node(int a, int b, int c, int d, short f, int g) 29 { 30 l = a, r = b, yl = c, yr = d, cover = f, len = g; 31 } 32 } a[maxn << 2]; 33 inline void build(int cur, int l, int r) //建立线段树 34 { 35 a[cur] = node(l, r, y[l], y[r], 0, 0); 36 if (l+1 == r) return ; 37 int mid = (l+r) >> 1; 38 build(lson, l, mid); 39 build(rson, mid, r); 40 } 41 42 inline void pushup(int cur) //计算当前cur结点覆盖的长度(纵向) 43 { 44 if (a[cur].cover > 0) a[cur].len = a[cur].yr - a[cur].yl; //当前结点被完全覆盖 45 else if (a[cur].l+1 == a[cur].r) a[cur].len = 0; //叶节点但已经被去除掉了(cover<=0) 46 else a[cur].len = a[lson].len + a[rson].len; //自身未被完全覆盖,向子节点求助 47 } 48 49 inline void updata(int cur, seg b) //更新i.e加入边操作 50 { 51 if (b.y1 == a[cur].yl && b.y2 == a[cur].yr) 52 { 53 //被加入的边完全覆盖 54 a[cur].cover += b.flag; //是否被抛弃 55 pushup(cur); //计算长度 56 return; 57 } 58 if (b.y2 <= a[rson].yl) updata(lson, b); 59 else if (b.y1 >= a[lson].yr) updata(rson, b); 60 else 61 { 62 seg tmp = b; //将b拆开付给lson rson 63 tmp.y2 = a[lson].yr; 64 updata(lson, tmp); 65 tmp = b, tmp.y1 = a[rson].yl; 66 updata(rson, tmp); 67 } 68 pushup(cur); 69 return; 70 } 71 int main() 72 { 73 int t, n; 74 int x1, x2, y1, y2; 75 LL area; 76 cin >> t; 77 while(t--) 78 { 79 m = 0; 80 scanf("%d", &n); 81 area = 0; 82 for (int i = 1; i <= n; i ++) 83 { 84 scanf("%d %d %d %d", &x1, &y1, &x2, &y2); 85 area += (LL)(x2 - x1) * (LL)(y2 - y1); 86 ss[++m] = seg(x1, y1, y2, 1), y[m] = y1; //建立扫描线 87 ss[++m] = seg(x2, y1, y2, -1), y[m] = y2; 88 } 89 if(area < 0 || area > 1000000000000000000ll) 90 { 91 cout << "Bad" << endl; 92 continue; 93 } 94 sort(ss+1,ss+1+m); 95 sort(y+1,y+1+m); //离散化 96 97 build(root, 1, m); //建树 98 LL sum(0); 99 for (int i = 1; i < m; i++) //依次加边 100 { 101 updata(root, ss[i]); 102 sum += (LL)a[root].len * (LL)(ss[i+1].x - ss[i].x); //计算此时面积 103 } 104 if(area == sum) 105 puts("Good"); 106 else 107 puts("Bad"); 108 } 109 return 0; 110 }