POJ 1151 Atlantis

首先,我得吐個槽。陶叔果然是個誠實的孩子,今天的題簡直坑爆了好麼?

先說A題,翻了一遍題目,覺得A題(SPOJ SUB_PROB)就是個KMP的模板題,心中大喜,套模板,欲A之,怎奈何居然是WA(我還提交了三遍T_T,再不濟你給個TLE我也可以接受啊)。於是重新讀題,發現應該拿AC自動機來搞!!!瞄一眼Rank,分析一下局勢,決定不理A題了,開了E題(Aizu 0024)。

由於E題是簽到水題(按照陶叔的話來說,什麼是簽到題捏?簽到題就是你A了以後能證明你來了的題~),果斷AC。接着順手開了F題(CodeForces 81A),發現F題也很水,是道堆棧的模擬題,以前有做過類似的題目,輕鬆A掉。看看錶才過了不到一個小時,暗自感嘆今天運氣還是不錯滴,喝口水,養個神,開D題(UVA 10319)。

由於英語太渣,讀題貌似出現了錯誤,天真的以爲是DFS,開心的碼完代碼,提交,WA。正在鬱悶的時候,看到了陶叔良心發現在公告裏給了Hint,尼瑪,2-SAT!思路差了八十條街,而且最坑爹的是,我讀錯題的DFS樣例居然過了!於是心情默默的不好了,關了OJ,開始各種騷擾劉文蔚學長。。。。。。

比完賽之後仔細看了看,其實C題(SPOJ RATING)挺好搞的,就是題目寫得不是特別順眼,一開始要是選這道的話,還是有可能A掉的~

好吧,吐完槽了,開始寫正經東西,線段樹的離散化和掃描線。

POJ上有一道題很經典,算是線段樹的進階吧,大家一起來看一下。

Description

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

Input

The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don't process it.

Output

For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
Output a blank line after each test case.

Sample Input

2
10 10 20 20
15 15 25 25.5
0

Sample Output

Test case #1
Total explored area: 180.00 

Source

題目意思很簡單,就是讓你求矩形的面積,重合的部分只算一次。解題的步驟大體來說分爲三步:

1)輸入數據,建樹。

2)離散化:將所有的x軸座標存在一個數組裏。

3)掃描線:從下到上掃描,更新區間計數。

圖片來自:紅黑聯盟-kk303




下面是完整的代碼:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 405
using namespace std;

struct node
{
      double l,r,y;//左端點,右端點,y軸高度
      int tp;//上下水平線標記
      bool operator < (node a) const// < 運算符重載,sort函數使用
      {
            return y < a.y;
      }
}line[MAXN << 2];

int n;
double X[MAXN << 2],Times[MAXN << 2],sum[MAXN];

int b_search(double x)//區間查找
{
      int l,r,mid;
      l = 0,r = n + 1;
      while (r - l > 1)
      {
            mid=(l + r) >> 1;
            if (X[mid] <= x) l = mid;
               else r = mid;
      }
      return l;//返回離散化的區間
}

void update(int x,int c,int l,int r,int now)
{
      if (l == r)
      {
            Times[x] += c;//區間計數修改
            if (Times[x]) sum[now]=X[x+1]-X[x]; //若區間計數爲正,得到區間長度
            if (!Times[x]) sum[now]=0;//若區間計數爲零,不計入長度
            return;
      }
      int mid = (l + r )/ 2;
      if (x <= mid) update(x,c,l,mid,now << 1);
      if (mid < x)  update(x,c,mid + 1,r,(now << 1) | 1);
      sum[now] = sum[now << 1] + sum[(now << 1) | 1];
      return;
}
int main()
{
      int i,j,T=0;
      double ans=0;
      while (~scanf("%d",&n) && n)
      {
            int num=0;
            for (i=1;i<=n;i++)
            {
                   double x1,y1,x2,y2;
                   scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);//錄入矩形的對角線端點

                   line[i*2-1].y = y1;//矩形水平線的y軸座標
                   line[i*2-1].l = x1;//水平線的左端點
                   line[i*2-1].r = x2;//水平線的右端點
                   line[i*2-1].tp = 1;//下水平線標記

                   line[i*2].y = y2;//矩形水平線的y軸座標
                   line[i*2].l = x1;//水平線的左端點
                   line[i*2].r = x2;//水平線的右端點
                   line[i*2].tp = -1;//上水平線標記

                   X[++num]=x1;//矩陣的左端點
                   X[++num]=x2;//矩陣的右端點
            }
            
            ans = 0;
            n = n * 2;//每個矩陣都有上下水平線
            
            sort(X + 1,X + 1 + num);//將所有X座標從小到大排序
            sort(line + 1,line + 1 + n);//將所有line按Y座標從小到大排序

            memset(sum,0,sizeof(sum));//掃描線掃到的合法長度
            memset(Times,0,sizeof(Times));//區間的計數數組

            for (i = 1;i <= n;i++)
            {
                   ans += sum[1] * (line[i].y - line[i - 1].y);//面積 = 每一段合法長度 * 高度
                   int l,r;
                   l = b_search(line[i].l);//離散化,獲取區間
                   r = b_search(line[i].r) - 1;//離散化,獲取區間
                   for (j = l;j <= r;j++)
                        update(j,line[i].tp,1,n-1,1);//掃描線更新操作
            }
            printf("Test case #%d\nTotal explored area: %.2f\n\n",++T,ans);
      }
      return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章