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
", t, ans);
156     }
157     return 0;
158 }
原文地址:https://www.cnblogs.com/gj-Acit/p/3886551.html