hdu4419 Colourful Rectangle

用扫描线扫一下,同时用线段树维护添加及删除的线段信息就好。
因为只需要检查根的信息就足够了,所以这棵线段树其实只需要上传信息。用0,1,…7八个数记录节点的不同颜色的覆盖情况,每次上传时根据子节点的信息及父节点的覆盖情况算出父节点的信息即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
#define clr(a) memset(a,0,sizeof(a))
struct nd{
    int l,r,x[5];
    ll le[8];
}tre[100010];
ll dr[20010];int dn;
void gentre(int l,int r,int ni){
    nd&p=tre[ni];
    clr(p.le),clr(p.x);
    p.l=l,p.r=r;
    if(l==r)
        p.le[0]=dr[r+1]-dr[l];
    else{
        int m=(l+r)>>1;
        gentre(l,m,ni<<1),gentre(m+1,r,ni<<1|1);
        p.le[0]=dr[r+1]-dr[l];
    }
};
void _upd(int ni){
    nd&p=tre[ni];
    int x=(p.x[1]?1:0)|(p.x[2]?2:0)|(p.x[4]?4:0),i;
    if(p.l==p.r){
        clr(p.le);
        p.le[x]=dr[p.r+1]-dr[p.l];
    }
    else{
        nd&l=tre[ni<<1],&r=tre[ni<<1|1];
        ll t[8];
        for(i=0;i<8;++i)t[i]=l.le[i]+r.le[i];
        for(clr(p.le),i=0;i<8;++i)
            p.le[i|x]+=t[i];
    }
};
void upd(int l,int r,int x,int cx,int ni){
    nd&p=tre[ni];
    if(p.l==l&&p.r==r){
        p.x[x]+=cx;
        _upd(ni);
    }
    else{
        int m=(p.l+p.r)>>1;
        if(r<=m)
            upd(l,r,x,cx,ni<<1);
        else if(l>m)
            upd(l,r,x,cx,ni<<1|1);
        else
            upd(l,m,x,cx,ni<<1),upd(m+1,r,x,cx,ni<<1|1);
        _upd(ni);
    }
};
struct ti{
    ll a,b,c;
    int x,cx;
}tr[20010];
bool timp(const ti&a,const ti&b){
    return a.c<b.c;
};
inline int _ts(char x){
    return x=='R'?1:x=='G'?2:4;
};
int bfi(ll x){
    int b=0,e=dn-1,m;
    while(1){
        m=(b+e)>>1;
        if(dr[m]==x)
            return m;
        else if(dr[m]<x)
            b=m+1;
        else
            e=m-1;
    }
};
int ct=0,n;char cz[5];ll rs[8];
int _opt[]={1,2,4,3,5,6,7};
void cl(){
    int i,j,k;ll a,b,c,d;
    scanf("%d",&n);
    for(i=j=0;i<n;++i){
        scanf("%s %I64d %I64d %I64d %I64d",cz,&a,&b,&c,&d);
        tr[j].a=b,tr[j].b=d,tr[j].c=a,tr[j].cx=1,tr[j].x=_ts(cz[0]);
        dr[j++]=b;
        tr[j].a=b,tr[j].b=d,tr[j].c=c,tr[j].cx=-1,tr[j].x=_ts(cz[0]);
        dr[j++]=d;
    }
    n<<=1;
    sort(dr,dr+n),sort(tr,tr+n,timp);
    dn=unique(dr,dr+n)-dr;
    gentre(0,dn-2,1);
    for(i=0;i<n&&tr[i].c==tr[0].c;++i)
        upd(bfi(tr[i].a),bfi(tr[i].b)-1,tr[i].x,tr[i].cx,1);
    for(clr(rs);i<n;){
        for(j=0;j<8;++j)
            rs[j]+=tre[1].le[j]*(tr[i].c-tr[i-1].c);
        for(j=i;i<n&&tr[i].c==tr[j].c;++i)
            upd(bfi(tr[i].a),bfi(tr[i].b)-1,tr[i].x,tr[i].cx,1);
    }
    for(printf("Case %d:\n",++ct),i=0;i<7;printf("%I64d\n",rs[_opt[i++]]));
};
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int t;scanf("%d",&t);
    while(t--)
        cl();
    return 0;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值