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

有点像HDU 3642的强化版。给你N个矩形的坐标,问题平面上被k个不同的矩形覆盖的面积是多少。

当初HDU 3642 是直接一个一个手写的,这里的k虽然说只有10,合并过成一个一个手写也是相当蛋疼的,不过仔细想一下,不难推出一般性的关系,然后直接用循环搞就好了。不过我还是因为有个地方忘记初始化WA了2发,真是弱o(╯□╰)o

注意每个房子代表一个点,而我们要把他转化成线段,对坐标进行一些简单的变换即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <bitset>
#include <list>
#include <cstdlib>
#include <climits>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <stack>
#include <sstream>
#include <numeric>
#include <fstream>
#include <functional>

using namespace std;

#define MP make_pair
#define PB push_back
#define lson rt << 1,l,mid
#define rson rt << 1 | 1,mid + 1,r
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int,int> pii;
const int INF = INT_MAX / 3;
const double eps = 1e-8;
const LL LINF = 1e17;
const double DINF = 1e60;
const int maxn = 3e4 + 20;

struct Seg {
    int x,l,r,cover;
    Seg(int x,int l,int r,int cover): x(x),l(l),r(r),cover(cover) {}
    bool operator < (const Seg &s) const {
        return x < s.x;
    }
};

int cnt[maxn << 4],sum[maxn << 4][11];
VI numy;
vector<Seg> seg;
int n,k;

void pushup(int rt,int l,int r) {
    int lc = rt << 1, rc = rt << 1 | 1;
    if(cnt[rt] >= k) {
        sum[rt][k] = numy[r + 1] - numy[l];
        for(int i = 1;i < k;i++) sum[rt][i] = 0;
    }
    else if(cnt[rt] == 0) {
        for(int i = 1;i <= k;i++) sum[rt][i] = sum[lc][i] + sum[rc][i];
    }
    else {
        int nowsum = 0;
        for(int i = k;i >= 1;i--) {
            if(i < cnt[rt]) sum[rt][i] = 0;
            else if(i == cnt[rt]) sum[rt][i] = numy[r + 1] - numy[l] - nowsum;
            else {
                sum[rt][i] = 0;
                for(int j = 1;j <= i;j++) if(j + cnt[rt] >= i) {
                    if(i == k) sum[rt][i] += sum[lc][j] + sum[rc][j];
                    else if(j + cnt[rt] == i) sum[rt][i] += sum[lc][j] + sum[rc][j];
                }
                nowsum += sum[rt][i];
            }
        }
    }
}
void update(int rt,int l,int r,int ql,int qr,int Val) {
    if(ql <= l && qr >= r) {
        cnt[rt] += Val; pushup(rt,l,r);
    }
    else {
        int mid = (l + r) >> 1;
        if(ql <= mid) update(lson,ql,qr,Val);
        if(qr > mid) update(rson,ql,qr,Val);
        pushup(rt,l,r);
    }
}

int getID(int Val) {
    return lower_bound(numy.begin(),numy.end(),Val) - numy.begin();
}

int main() {
    int T,x1,y1,x2,y2; scanf("%d",&T);
    for(int kase = 1;kase <= T;kase++) {
        scanf("%d%d",&n,&k);
        numy.clear(); seg.clear();
        for(int i = 0;i < n;i++) {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            seg.PB(Seg(x1,y1,y2 + 1,1));
            seg.PB(Seg(x2 + 1,y1,y2 + 1,-1));
            numy.PB(y1); numy.PB(y2 + 1);
        }
        sort(numy.begin(),numy.end());
        sort(seg.begin(),seg.end());
        numy.erase(unique(numy.begin(),numy.end()),numy.end());
        int ks = seg.size(), ky = numy.size();
        LL ans = 0;
        for(int i = 0;i < ks;i++) {
            int ql = getID(seg[i].l), qr = getID(seg[i].r) - 1;
            update(1,0,ky - 1,ql,qr,seg[i].cover);
            if(i < ks - 1) {
                ans += 1LL * (seg[i + 1].x - seg[i].x) * sum[1][k];
            }
        }
        cout << "Case " << kase << ": " << ans << endl;
    }
    return 0;
}

  

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

时间: 2024-10-16 06:58:21

UVA 11983 Weird Advertisement 线段树+离散化+扫描线的相关文章

UVA 11983 - Weird Advertisement(线段树)

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

uva 11983 - Weird Advertisement(线段树)

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

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 题目大意是说给你N个矩形,让你求被覆盖k次以上的点的总个数(x,y<1e9) 首先这个题有一个转化,吧每个矩形的x2,y2+1这样就转化为了求N个矩形被覆盖k次以上的区域的面积 由于坐标很大,首先考虑的就是将坐标离散化,然后建立线段树tree[][K],表示x的某个区间被覆盖了K次(大于K次算K次)的实际长度,在计算时把矩形转化为一系列横线段(就是说将一个矩形拆开为两条线段,下面的标记为1,上面的标记为-1(这里的标记很有技巧)),然后将这些线段按照y值的从小到达排序(y值相

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

hdu1828 Picture(线段树+离散化+扫描线)两种方法

C - Picture Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or

POJ 2482 Stars in Your Window 线段树+离散化+扫描线

题面据说很美- 每个星星可以根据在窗口的左下角和右上角两个位置建立两条扫描线,之后就是简单的区间增减和求最大值操作了. 注意要处理在边界上的星星是不算的情况,其实只要把左右边界分别增减一个eps即可. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

poj3277--City Horizon(线段树+离散化+扫描线)

City Horizon Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16206   Accepted: 4414 Description Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouette