hdu4419 Colourful Rectangle(离散,线段树,线扫描,状压)

由于状态有点多,我们用状压的思想来做这道题,用1,2,4分别来表示三原色,其他的就和线扫描一样了!这样是比较简单的做法了,当然也可以用最原始的做法!不过嘛就是有点麻烦了!

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define nn 10005
#define LL __int64
#define root 1,m,1
int biao[300];
struct seg
{
    int l,r,h,f,rbg;
}s[nn<<1];
int pos[nn<<1];
int col[nn<<4][8];
int yan[nn<<4][3];
bool cmp(seg a,seg b)
{
    return a.h<b.h;
}
int binary(int v,int low,int top)
{
    while(low<=top)
    {
        int mid=(low+top)>>1;
        if(pos[mid]==v) return mid;
        else if(pos[mid]>v) top=mid;
        else low=mid+1;
    }
    return -1;
}
void pushup(int l,int r,int rt)
{
    int t=0;
    for(int i=0;i<3;i++)
        if(yan[rt][i])
            t=t|(1<<i);//表示该区间的状态
    for(int i=0;i<8;i++)
        col[rt][i]=0;
    int all=pos[r+1]-pos[l];
    for(int i=1;i<8;i++)
        col[rt][i|t]+=col[rt<<1][i]+col[rt<<1|1][i];//i|t表示由i更可得到的状态
    for(int i=1;i<8;i++)
        all-=col[rt][i];
    col[rt][t]+=all;//未更新的表示只有改颜色的长度
}
void updata(int ll,int rr,int cl,int x,int l,int r,int rt)
{
    if(ll>r||rr<l)  return;
    if(ll<=l&&r<=rr)
    {
        yan[rt][cl]+=x;
        pushup(l,r,rt);
        return;
    }
    int mid=(l+r)>>1;
    updata(ll,rr,cl,x,l,mid,rt<<1);
    updata(ll,rr,cl,x,mid+1,r,rt<<1|1);
    pushup(l,r,rt);
}
int main()
{
    biao['R']=0;
    biao['G']=1;
    biao['B']=2;
    int t;
    int Case=1;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int num=0;
        for(int i=0;i<n;i++)
        {
            char a[2];
            int x1,x2,y1,y2;
            scanf("%s%d%d%d%d",a,&x1,&y1,&x2,&y2);
            s[num].l=x1; s[num].r=x2; s[num].h=y1; s[num].f=1;  s[num++].rbg=biao[a[0]];
            s[num].l=x1; s[num].r=x2; s[num].h=y2; s[num].f=-1; s[num].rbg=biao[a[0]];
            pos[num-1]=x1; pos[num++]=x2;
        }
        sort(pos,pos+num);
        sort(s,s+num,cmp);
        int m=1;
        for(int i=1;i<num;i++)
        {
            if(pos[i]!=pos[i-1])
                pos[m++]=pos[i];
        }
        LL ans[8];
        memset(yan,0,sizeof(yan));
        memset(col,0,sizeof(col));
        memset(ans,0,sizeof(ans));
        int st=0;
        for(int i=0;i<num;i++)
        {
            int l=binary(s[i].l,0,m-1);
            int r=binary(s[i].r,0,m-1)-1;
            for(int j=1;j<8;j++)
                ans[j]+=(LL)col[1][j]*(s[i].h-st);
            st=s[i].h;
            updata(l,r,s[i].rbg,s[i].f,0,m-1,1);
        }
        printf("Case %d:\n",Case++);
        printf("%I64d\n",ans[1]);
        printf("%I64d\n",ans[2]);
        printf("%I64d\n",ans[4]);
        printf("%I64d\n",ans[3]);
        printf("%I64d\n",ans[5]);
        printf("%I64d\n",ans[6]);
        printf("%I64d\n",ans[7]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值