HDU 4419 扫描线+线段树

自己的思路:题目给了三种颜色  R G B,能够组成7种颜色,我想到用状态压缩(R =1,G=2,B=4),因为他的颜色是由他的种类数决定的,所以我用异或来表示他的覆盖情况(这是我傻逼的地方,我没理解基础的 +1,-1 为什么),后面debug发现我的覆盖情况出现的负值的情况,然后就没有思路了。

 

大佬博客:https://blog.csdn.net/ACM_cxlove/article/details/8015043

大佬思路:大佬用一个数组记录每个颜色出现的情况,其实就是+1,-1的情况(颜色出现到消失),还有一个我没想到的地方,就是更新长度的时候,如果这个区间被全部覆盖,当用儿子来更新父亲的时候,原本的颜色会减少,新的颜色会变多。

我是真的菜!Orz。。。

代码:

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const int MAXN=1e5;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;

struct node
{
    ll l;
    ll r;
    ll h;
    ll status;
    bool friend operator<(node a,node b)
    {
        return a.h<b.h;
    }
}line[20005];
ll x[20005];

struct xx
{
    ll s[5];
    ll sum[8];
}root[80005];

int judge(char x)
{
    if(x=='R')
        return 1;
    if(x=='G')
        return 2;
    return 4;
}

void pushup(int sign,int l,int r)
{
    int s=(root[sign].s[1]>0?1:0)|(root[sign].s[2]>0?2:0)|(root[sign].s[4]>0?4:0);
    if(s)   ///区间被全部覆盖
    {
        memset(root[sign].sum,0,sizeof(root[sign].sum));
        root[sign].sum[s]=x[r+1]-x[l];      ///区间长度
        for(int i=1;i<=7;i++)
        {
            if(s!=(s|i))        ///如果原来有其他颜色
            {
                ll add=root[sign<<1].sum[i]+root[sign<<1|1].sum[i];
                root[sign].sum[s|i]+=add;   ///混合的颜色增多
                root[sign].sum[s]-=add;     ///原本的颜色减少
            }
        }
    }
    else if(l==r)   ///叶子节点
        memset(root[sign].sum,0,sizeof(root[sign].sum));
    else            ///区间没有被完全覆盖,由儿子更新父亲
    {
        for(int i=0;i<=7;i++)
            root[sign].sum[i]=root[sign<<1].sum[i]+root[sign<<1|1].sum[i];
    }
}

void updateroot(int sign,int l,int r,int a,int b,int f)
{
    if(l==a&&r==b)  ///更新覆盖情况
    {
        if(f>0)
            root[sign].s[f]++;
        else
            root[sign].s[-f]--;
        pushup(sign,l,r);
        return ;
    }
    int mid=(l+r)>>1;
    if(b<=mid)
        updateroot(sign<<1,l,mid,a,b,f);
    else if(a>mid)
        updateroot(sign<<1|1,mid+1,r,a,b,f);
    else
    {
        updateroot(sign<<1,l,mid,a,mid,f);
        updateroot(sign<<1|1,mid+1,r,mid+1,b,f);
    }
    pushup(sign,l,r);
}
int main()
{
    ll t,n;
    ll x1,y1,x2,y2;
    char a[5];
    scanf("%lld",&t);
    for(int u=1;u<=t;u++)
    {
        memset(root,0,sizeof(root));
        int sign=0;
        scanf("%lld",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s %lld %lld %lld %lld",a,&x1,&y1,&x2,&y2);
            ll p=judge(a[0]);       ///判断颜色
            line[++sign]=node{x1,x2,y1,p};
            x[sign]=x1;
            line[++sign]=node{x1,x2,y2,-p};
            x[sign]=x2;
        }
        sort(line+1,line+1+sign);
        sort(x+1,x+1+sign);
        int d=unique(x+1,x+1+sign)-(x+1);
        ll ans[10]={0};
        for(int i=1;i<sign;i++)
        {
            int b=lower_bound(x+1,x+1+d,line[i].l)-x;
            int c=lower_bound(x+1,x+1+d,line[i].r)-x-1;
            updateroot(1,1,d-1,b,c,line[i].status);
            if(line[i+1].h!=line[i].h)
            {
                for(int j=1;j<=7;j++)
                    ans[j]+=root[1].sum[j]*(line[i+1].h-line[i].h);
            }
        }
        printf("Case %d:\n",u);
        swap(ans[4],ans[3]);///因为输出顺序是1 2 4 3 5 6 7,换一下顺序方便输出
        for(int i=1;i<=7;i++)
            printf("%lld\n",ans[i]);
    }
    return 0;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值