uva 11985

题意:给你一堆矩形的左下角与右上角坐标,问在直角坐标系里,被覆盖k次(包括k次以上)的点(整数点)有多少个。
思路:因为边上覆盖点的也算在里面,那么把矩形右上角的坐标(x2,y2)分别+1,那么这个点数就变成了这个矩形的面积了。另外数据范围很大,所以要离散化,具体见代码。
代码实现与一般的矩形面积并差别不大,关键是lazy标记,一般的矩形面积并有个sum[rt]和一个cnt[rt],这里cnt如果等于>0,那么也就是说这个区间被完全覆盖了,算的时候用r+1-l即可, 如果cnt==0,表示没有被完全覆盖,那么覆盖了多长呢,那么sum就由左右儿子决定。这道题用的就是cnt>1的时候它的具体含义。
void pushup(int l,int r,int rt)
{
    if(cnt[rt]) sum[rt]=hs[r+1]-hs[l];
    else if(l==r) sum[rt]=0;
    else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}


sum[maxn][i],表示该区间被i次覆盖的长度,cnt[rt]表示该区间被覆盖的次数。我们要的是sum[1][k];
1.那么如果cnt[rt]>=k,那么sum[rt]][k]=hs[r+1]-hs[l];
2.如果l==r,说明是叶子节点,sum[rt][cur[rt]]=hs[r+1]-hs[l];
3.如果cnt<k,也就是说这个区间没有被覆盖k次,那么就不能这么算了,那么就要由左右儿子来更新这些sum[rt][i];
       
memset(sum[rt],0,sizeof(sum[rt]));      
        for(int i=cnt[rt]; i<=K; i++)
            sum[rt][i] += sum[rt<<1][i-cnt[rt]] + sum[rt<<1|1][i-cnt[rt]];
        //因为它现在是cnt[rt](这个区间已经全部被覆盖了cnt[rt]次),那么这个区间被覆盖cnt[rt]以上次数的长度怎么弄,要达到i次,那就是它的左右儿子被覆盖i-cnt[rt]次的长度相加即可(这个不难理解);
        for(int i=K-cnt[rt]+1; i<=K; i++)
            sum[rt][K] += sum[rt<<1][i] + sum[rt<<1|1][i];
        //上面的一个循环是k次及k次以下的更新,那么K次以上的呢,K次以上的长度都会加到sum[rt][K]中去,那么左右儿子被覆盖的次数从K-cnt[rt]+1开始到K,这些都加到sum[rt][K]就是该区间被覆盖K次以上的长度。
这样也就ok了。如果还不明白可以去做一下hdu1255这道题,这个是覆盖两次,比较好理解。
贴个别人的hdu1255的链接
http://www.cnblogs.com/scau20110726/archive/2013/04/14/3020998.html
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define ll long long
using namespace std;
const int maxn=60005;

struct node
{
    ll l,r,h;
    int s;
    node() {}
    node(double a,double b,double c,int s):l(a),r(b),h(c),s(s) {}
    bool operator < (const node &cmp) const
    {
        return h < cmp.h;
    }
};
int cnt[maxn<<2];
ll sum[maxn<<2][15];
node seg[maxn<<2];
ll hs[maxn<<2];
int K;

void pushup(int l,int r,int rt)
{
    memset(sum[rt],0,sizeof(sum[rt]));
    if(cnt[rt]>=K) sum[rt][K]=hs[r+1]-hs[l];//如果这个节点被覆盖就大于等于k了那么不需要管了
    else if(l==r) sum[rt][cnt[rt]]=hs[r+1]-hs[l];//如果这个节点是子节点了,那么
    else//?
    {
        for(int i=cnt[rt]; i<=K; i++)
            sum[rt][i] += sum[rt<<1][i-cnt[rt]] + sum[rt<<1|1][i-cnt[rt]];
        for(int i=K-cnt[rt]+1; i<=K; i++)
            sum[rt][K] += sum[rt<<1][i] + sum[rt<<1|1][i];
    }
}

void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        cnt[rt]+=c;
        pushup(l,r,rt);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) update(L,R,c,lson);
    if(mid<R) update(L,R,c,rson);
    pushup(l,r,rt);
}

int binary(ll k,int m,ll h[]) //二分
{
    int l=0,r=m-1;
    int mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(hs[mid]==k) return mid;
        if(hs[mid]>k) r=mid-1;
        else l=mid+1;
    }
    return -1;
}

void build(int l,int r,int rt)
{
    cnt[rt]=0;
    memset(sum[rt],0,sizeof(sum[rt]));
    sum[rt][0]=hs[r+1]-hs[l];
    if(l==r) return;
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
}

int main()
{
    ll a,b,c,d;
    int n;
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        scanf("%d%d",&n,&K);
        int m=0;
        for(int i=0; i<n; i++)
        {
            cin>>a>>b>>c>>d;
            c++,d++;
            hs[m]=a;
            seg[m++]=node(a,c,b,1);
            hs[m]=c;
            seg[m++]=node(a,c,d,-1);
        }
        memset(sum,0,sizeof(sum));
        memset(cnt,0,sizeof(cnt));
        sort(hs,hs+m);
        sort(seg,seg+m);
        int ans=1;
        ll area=0;
        for(int i=1; i<m; i++)
        {
            if(hs[i]!=hs[i-1]) hs[ans++]=hs[i];
        }
        build(0,ans-1,1);
        for(int i=0; i<m-1; i++)
        {
            int l=binary(seg[i].l,ans,hs);
            int r=binary(seg[i].r,ans,hs)-1;
            if(l<=r) update(l,r,seg[i].s,0,ans-1,1);
            area+=sum[1][K]*(seg[i+1].h-seg[i].h);
        }
        printf("Case %d: %lld\n", cas++, area);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值