UVA 11983 Weird Advertisement(线段树求矩形并的面积)

UVA 11983

题目大意是说给你N个矩形,让你求被覆盖k次以上的点的总个数(x,y<1e9)

首先这个题有一个转化,吧每个矩形的x2,y2+1这样就转化为了求N个矩形被覆盖k次以上的区域的面积

由于坐标很大,首先考虑的就是将坐标离散化,然后建立线段树tree[][K],表示x的某个区间被覆盖了K次(大于K次算K次)的实际长度,在计算时把矩形转化为一系列横线段(就是说将一个矩形拆开为两条线段,下面的标记为1,上面的标记为-1(这里的标记很有技巧)),然后将这些线段按照y值的从小到达排序(y值相同的按照标记为-1的排在前,为1的排在后)

然后考虑从下往上依次拿出第一条线段(x1, x2, y, flag),将x1, x2整个区间tree[x1,x2][1]更新为x1到x2覆盖了1次的实际长度,之后每取出一条线段先计算与上一条线段的高度差,乘上整个区间被覆盖K次的总长度,便的到了当前覆盖K次的结果,然后按照当前线段的flag值更新线段树

若flag=1说明它是一条起始边,说明后面的x1,x2这个区间被覆盖的次数加1,更新线段树x1,x2区间被覆盖k次(0<k<=K)的总长+[x1, x2]的实际长度

若flag=-1说说明这是一条结束边,x1,x2这个区间的被覆盖次数应当-1,所以与上面相反,减去这个区间的实际长度即可

同时由于y相同的是先算的-1的线段,保证了这个矩形没有继续和后方的矩形继续相交,所以结果是准确的

不理解时可以按照思路画一个图模拟一下,便可以很好理解

  1 #include <map>
  2 #include <set>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <vector>
  8 #include <cstdio>
  9 #include <cctype>
 10 #include <cstring>
 11 #include <cstdlib>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 #define INF 1e9
 16 #define inf (-((LL)1<<40))
 17 #define lson k<<1, L, mid
 18 #define rson k<<1|1, mid+1, R
 19 #define mem0(a) memset(a,0,sizeof(a))
 20 #define mem1(a) memset(a,-1,sizeof(a))
 21 #define mem(a, b) memset(a, b, sizeof(a))
 22 #define FOPENIN(IN) freopen(IN, "r", stdin)
 23 #define FOPENOUT(OUT) freopen(OUT, "w", stdout)
 24 template<class T> T CMP_MIN(T a, T b) { return a < b; }
 25 template<class T> T CMP_MAX(T a, T b) { return a > b; }
 26 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
 27 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
 28 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
 29 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
 30
 31 //typedef __int64 LL;
 32 typedef long long LL;
 33 const int MAXN = 30005;
 34 const int MAXM = 100005;
 35 const double eps = 1e-10;
 36 const int MOD = 9901;
 37
 38 int N, K, T;
 39 LL Hash[MAXN<<1], cntHash;
 40 int cnt[MAXN<<3], len[MAXN<<3][12];
 41 struct Line {
 42     LL x1, x2, y;
 43     int flag;
 44     Line(){}
 45     Line(LL _x1, LL _x2, LL _y, int _flag)
 46     {
 47         x1 = _x1;
 48         x2 = _x2;
 49         y = _y;
 50         flag = _flag;
 51     }
 52     bool operator < (const Line& A)const
 53     {
 54         if(y != A.y) return y < A.y;
 55         return flag < A.flag;
 56     }
 57 }line[MAXN<<1];
 58
 59 int bsearch(int low, int high, int num)
 60 {
 61     while(low <= high)
 62     {
 63         int mid = (low + high) >> 1;
 64         if(Hash[mid] == num) return mid;
 65         if(Hash[mid] > num) high = mid - 1;
 66         else low = mid + 1;
 67     }
 68     return 0;
 69 }
 70
 71 void buildTree(int k, int L, int R)
 72 {
 73     cnt[k] = 0; mem0(len[k]);
 74
 75     len[k][0] = Hash[R+1] - Hash[L];
 76
 77     if(L == R) return ;
 78
 79     int mid = (L + R) >> 1;
 80
 81     buildTree(lson);    buildTree(rson);
 82 }
 83
 84 void updateCur(int k, int L, int R)
 85 {
 86     mem0(len[k]);
 87     if(cnt[k] >= K)
 88         len[k][K] = Hash[R+1] - Hash[L];
 89     else if(L == R)
 90         len[k][cnt[k]] = Hash[R+1] - Hash[L];
 91     else {
 92         for(int i=cnt[k];i<=K;i++)
 93             len[k][i] += len[k<<1][i-cnt[k]] + len[k<<1|1][i-cnt[k]];
 94         for(int i=K-cnt[k]+1;i<=K;i++)
 95             len[k][K] += len[k<<1][i] + len[k<<1|1][i];
 96     }
 97 }
 98
 99 void update(int k, int L, int R, int l, int r, int flag)
100 {
101     if(R < l || r < L) return ;
102
103     if(l<=L && R<=r) { cnt[k] += flag; updateCur(k, L, R); return ; }
104
105     int mid = (L + R) >> 1;
106
107     update(lson, l, r, flag);    update(rson, l, r, flag);
108
109     updateCur(k, L, R);
110 }
111
112 void init()
113 {
114     int x1, x2, y1, y2;
115     scanf("%d %d", &N, &K);
116     for(int i=1;i<=N;i++)
117     {
118         scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
119          ++ x2; ++ y2;
120         line[i] = Line(x1, x2, y1, 1);
121         line[i+N] = Line(x1, x2, y2, -1);
122         Hash[i] = x1;
123         Hash[i+N] = x2;
124     }
125     sort(line + 1, line + 2*N + 1);
126
127     sort(Hash + 1, Hash + 2*N + 1);
128     cntHash = 0;
129     for(int i = 1; i <= N*2; i ++ )
130       if(i==1 || Hash[i-1] != Hash[i])
131         Hash[++cntHash] = Hash[i];
132
133     buildTree(1, 1, cntHash-1);
134 }
135
136 int main()
137 {
138     //FOPENIN("in.txt");
139     scanf("%d", &T);
140     for(int t = 1; t <= T; t ++ )
141     {
142         init();
143         LL ans = 0;
144         for(int i = 1; i <= 2 * N; i ++ )
145         {
146             if(i != 1)
147             {
148                 ans += (line[i].y - line[i-1].y) * len[1][K];
149             }
150             int l  = bsearch(1, cntHash, line[i].x1);
151             int r = bsearch(1, cntHash, line[i].x2);
152             update(1, 1, cntHash-1, l, r-1, line[i].flag);
153         }
154
155         printf("Case %d: %lld\n", t, ans);
156     }
157     return 0;
158 }

UVA 11983 Weird Advertisement(线段树求矩形并的面积)

时间: 2024-08-11 17:04:24

UVA 11983 Weird Advertisement(线段树求矩形并的面积)的相关文章

UVA 11983 Weird Advertisement --线段树求矩形问题

题意:给出n个矩形,求矩形中被覆盖K次以上的面积的和. 解法:整体与求矩形面积并差不多,不过在更新pushup改变len的时候,要有一层循环,来更新tree[rt].len[i],其中tree[rt].len[i]表示覆盖次数大于等于i的线段长度,以便求面积,最后只要每次都用tree[1].len[K]来算面积即可. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cst

UVA 11983 - Weird Advertisement(线段树)

UVA 11983 - Weird Advertisement 题目链接 题意:给定几个矩形,之后,求覆盖k次以上的点 思路:先把坐标离散化掉,然后把每个矩形x2,y1加一,这样就把求点转化为求面积,然后每个矩形拆分成上下两个线段,按y排序之后,从下往上每访问一条线段(第一条除外),答案就加上目前整条线段上次数大于等于k的长度乘上这条线段和上一条线段的高度差,然后再用这条线段,根据它是矩形下面还是上面的线段去更新整条线段,维护线段大于等于k的长度这步利用线段树 代码: #include <cst

UVA 11983 Weird Advertisement 线段树+离散化+扫描线

有点像HDU 3642的强化版.给你N个矩形的坐标,问题平面上被k个不同的矩形覆盖的面积是多少. 当初HDU 3642 是直接一个一个手写的,这里的k虽然说只有10,合并过成一个一个手写也是相当蛋疼的,不过仔细想一下,不难推出一般性的关系,然后直接用循环搞就好了.不过我还是因为有个地方忘记初始化WA了2发,真是弱o(╯□╰)o 注意每个房子代表一个点,而我们要把他转化成线段,对坐标进行一些简单的变换即可. #include <cstdio> #include <cstring> #

uva 11983 - Weird Advertisement(线段树)

题目链接:uva 11983 - Weird Advertisement 题目大意:给定n个矩形,问说有多少区域的面积被覆盖k次以上. 解题思路:将每个矩形差分成两条线段,一段为添加覆盖值1,一段为减少覆盖值1,同时记录两段的高度(横坐标).然后对纵坐标离散化建立线段树,然后对线段按照高度排序,维护整段区间中覆盖度大于K的长度,乘上高度上的范围即可. #include <cstdio> #include <cstring> #include <vector> #incl

UVA - 11983 Weird Advertisement (线段树求并面积)

Description G Weird Advertisement Renat Mullakhanov (rem), one of the most talented programmers in the world, passed away on March 11, 2011. This is very sad news for all of us. His team went to ACM ICPC World Finals - 2004, placed 4th and won gold m

POJ&#183;1151 Atlantis&#183;线段树求矩形面积并

题目在这:http://poj.org/problem?id=1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K 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 is

uva 11983 Weird Advertisement 扫描线

Weird Advertisement Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=18802 Description 2DPlaneLand is a land just like a huge 2D plane. The range of X axis is 0 to 109 and the range ofY axis

HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 num: 此区间分离开的线段的条数 重点在转移的地方,不难理解. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cstdio> #include <cstrin

POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线段树维护两个值:cover和len,cover表示该线段区间目前被覆盖的线段数目,len表示当前已覆盖的线段长度(化为离散前的真值),每次加入一条线段,将其y_low,y_high之间的区间染上line[i].cover,再以tree[1].len乘以接下来的线段的x坐标减去当前x坐标,即计算了一部