首页 > 代码库 > UVA 11983 Weird Advertisement(线段树求矩形并的面积)

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 }