HDU - 6183 Color it —— CDQ+线段树+状压求二维区间不同数的个数 vector?

96 篇文章 1 订阅
8 篇文章 0 订阅

This way

题意:

有4种操作:
0:清空所有记录
1 x y c:在x,y这个点添加一个c。
2 x y1 y2:问你从(1,y1)到(2,y2)这个区间内有多少不同的数。
3: 退出

题解:

1.vector

不知道为什么vector暴力可以过,,是不是数据的问题。直接开51个vector,查询的时候直接暴力查每个vector里是否有落在这个范围内的点:

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int x,y;
};
vector<node>s[51];
int main()
{
    int op,x,y1,y2,c,n=0;
    while(scanf("%d",&op))
    {
        if(op==3)
            return 0;
        if(op==0)
        {
            for(int i=0;i<=50;i++)
                s[i].clear();
        }
        else if(op==1)
        {
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            s[c].push_back({x,y});
        }
        else
        {
            int x,y1,y2,ans=0;
            scanf("%d%d%d",&x,&y1,&y2);
            for(int i=0;i<=50;i++)
            {
                for(int j=0;j<s[i].size();j++)
                {
                    if(s[i][j].x<=x&&s[i][j].y>=y1&&s[i][j].y<=y2)
                    {
                        ans++;
                        break;
                    }
                }
            }
            printf("%d\n",ans);

        }
    }
}

2.CDQ+线段树

好像可以直接用主席树开点的方式做线段树,但是CDQ也可以。
正常的三维CDQ,第一维是输入顺序,第二维是x从小到大归并排序,第三维注意如果用51个树状数组会MLE,TLE,暂时没找到啥方法可以用树状数组卡过去,线段树的话可以用状压维护这个区间内的值,因为只有51种值,那么用(1<<c)表示是否有这个值,区间不同数的话只需要位或操作即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=150005;
struct node
{
    int op,x,y1,y2,id;
    ll c;
}q[N],tmp[N];
int a[N*2];
int op,n=0,all=0,que=0;
ll ans[N],num[N*4];
void update(int l,int r,int root,int pos,int o,ll val)
{
    if(l==r)
    {
        if(o==1)
            num[root]|=(1ll<<val);
        else
            num[root]=0;
        return ;
    }
    int mid=l+r>>1;
    if(mid>=pos)
        update(l,mid,root<<1,pos,o,val);
    else
        update(mid+1,r,root<<1|1,pos,o,val);
    num[root]=num[root<<1]|num[root<<1|1];
}
ll query(int l,int r,int root,int ql,int qr)
{
    if(l>=ql&&r<=qr)
        return num[root];
    int mid=l+r>>1;
    ll ans=0;
    if(mid>=ql)
        ans=ans|query(l,mid,root<<1,ql,qr);
    if(mid<qr)
        ans=ans|query(mid+1,r,root<<1|1,ql,qr);
    return ans;
}
void CDQ(int l,int r)
{
    if(l==r)
        return ;
    int mid=l+r>>1;
    CDQ(l,mid),CDQ(mid+1,r);
    int p1=l,p2=mid+1,t=0;
    while(p1<=mid&&p2<=r)
    {
        if(q[p1].x<=q[p2].x)
        {
            if(q[p1].op==1)
                update(1,all,1,q[p1].y1,1,q[p1].c);
            tmp[++t]=q[p1],p1++;
        }
        if(q[p1].x>q[p2].x)
        {
            if(q[p2].op==2)
                ans[q[p2].id]|=query(1,all,1,q[p2].y1,q[p2].y2);
            tmp[++t]=q[p2],p2++;
        }
    }
    while(p1<=mid)
        tmp[++t]=q[p1++];
    while(p2<=r)
    {
        if(q[p2].op==2)
            ans[q[p2].id]|=query(1,all,1,q[p2].y1,q[p2].y2);
        tmp[++t]=q[p2],p2++;
    }
    for(int i=1;i<=t;i++)
    {
        q[l+i-1]=tmp[i];
        if(tmp[i].op==1)
            update(1,all,1,tmp[i].y1,-1,tmp[i].c);
    }
}
int main()
{
    while(scanf("%d",&op))
    {
        if(op==3)
        {
            sort(a+1,a+1+all);
            all=unique(a+1,a+1+all)-a-1;
            for(int i=1;i<=n;i++)
            {
                q[i].y1=lower_bound(a+1,a+1+all,q[i].y1)-a;
                if(q[i].op==2)
                    q[i].y2=lower_bound(a+1,a+1+all,q[i].y2)-a;
            }
            CDQ(1,n);
            for(int i=1;i<=que;i++)
            {
                int sum=0;
                for(ll j=0;j<=50;j++)
                    if((ans[i]&(1ll<<j)))
                        sum++;
                printf("%d\n",sum);
                ans[i]=0;
            }
            n=all=que=0;
            return 0;
        }
        if(op==0)
        {
            if(!all)
                continue;
            sort(a+1,a+1+all);
            all=unique(a+1,a+1+all)-a-1;
            for(int i=1;i<=n;i++)
            {
                q[i].y1=lower_bound(a+1,a+1+all,q[i].y1)-a;
                if(q[i].op==2)
                    q[i].y2=lower_bound(a+1,a+1+all,q[i].y2)-a;
            }
            CDQ(1,n);
            for(int i=1;i<=que;i++)
            {
                int sum=0;
                for(ll j=0;j<=50;j++)
                    if((ans[i]&(1ll<<j)))
                        sum++;
                printf("%d\n",sum);
                ans[i]=0;
            }
            n=all=que=0;
            continue;
        }
        if(op==1)
        {
            scanf("%d",&q[++n].x);
            scanf("%d",&q[n].y1);
            scanf("%lld",&q[n].c);
            q[n].op=1,a[++all]=q[n].y1;
        }
        else if(op==2)
        {
            scanf("%d",&q[++n].x);
            scanf("%d",&q[n].y1);
            scanf("%d",&q[n].y2);
            q[n].op=2;
            a[++all]=q[n].y1,a[++all]=q[n].y2,q[n].id=++que;
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值