HDU 6183 Color it [KDtree+位压缩]

6 篇文章 0 订阅
1 篇文章 0 订阅
题意:在一个二维坐标系中,每次有两个操作:
①向一个点加入一种颜色。

②询问矩形区域[1,y1],[x,y2]范围内的不同颜色的数量。

题解:KDtree中64位sum记录每个节点的不用颜色的情况,或操作统计答案。

AC代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
const int mxn=350010;
struct node
{
    int l,r;
    int min[2],max[2];
    int d[2];
    LL w;
    LL sum;
}t[mxn];
int root=0,nowD;
int cmp(const node a,const node b)
{
    return a.d[nowD]<b.d[nowD];
}
int cnt;
int lim=0;
inline void pushup(int rt,int x)
{
    t[rt].max[0]=max(t[rt].max[0],t[x].max[0]);
    t[rt].max[1]=max(t[rt].max[1],t[x].max[1]);
    t[rt].min[0]=min(t[rt].min[0],t[x].min[0]);
    t[rt].min[1]=min(t[rt].min[1],t[x].min[1]);
    return;
}
inline bool in(int x1,int y1,int x2,int y2,int k)
{
    return (x1<=t[k].min[0]&&t[k].max[0]<=x2&&y1<=t[k].min[1]&&t[k].max[1]<=y2);
}
inline bool out(int x1,int y1,int x2,int y2,int k)
{
    return (x1>t[k].max[0]||x2<t[k].min[0]||y1>t[k].max[1]||y2<t[k].min[1]);
}
int Build(int l,int r,int D)
{
    if(l>r)return 0;
    nowD=D;int mid=(l+r)>>1;
    nth_element(t+l,t+mid,t+r+1,cmp);///
    t[mid].max[0]=t[mid].min[0]=t[mid].d[0];
    t[mid].max[1]=t[mid].min[1]=t[mid].d[1];
    t[mid].sum=t[mid].w;
    //
    t[mid].l=Build(l,mid-1,D^1);
    if(t[mid].l)pushup(mid,t[mid].l);
    t[mid].r=Build(mid+1,r,D^1);
    if(t[mid].r)pushup(mid,t[mid].r);
    //
    t[mid].sum=t[mid].w|t[t[mid].l].sum|t[t[mid].r].sum;
    return mid;
}
void insert(int &now,int x,int D)
{
    if(!now){now=x;return;}
    if(t[x].d[D]==t[now].d[D] && t[x].d[!D]==t[now].d[!D])
	{
        t[now].w|=t[x].w;
        t[now].sum|=t[x].w;
        --cnt;
        return;
    }
    if(t[x].d[D]<t[now].d[D])
	{
        insert(t[now].l,x,D^1);
        pushup(now,t[now].l);
    }
    else
	{
        insert(t[now].r,x,D^1);
        pushup(now,t[now].r);
    }
    t[now].sum=t[now].w|t[t[now].l].sum|t[t[now].r].sum;
    return;
}
LL query(int rt,int x1,int y1,int x2,int y2)
{
    if(!rt)return 0;
    LL res=0;
    if(in(x1,y1,x2,y2,rt)){return t[rt].sum;}
    if(out(x1,y1,x2,y2,rt)){return 0;}
    if(x1<=t[rt].d[0]&&t[rt].d[0]<=x2&&y1<=t[rt].d[1]&&t[rt].d[1]<=y2)res|=t[rt].w;
    res|=query(t[rt].l,x1,y1,x2,y2)|query(t[rt].r,x1,y1,x2,y2);
    return res;
}
int main()
{
    int i,j,op,x,y,w;
    lim=9000;
    LL lans=0;int X1,X2,Y1,Y2;
    while(1)
	{
        scanf("%d",&op);
        if(op==3)break;
        if(op==1)
		{
			cnt++;scanf("%d%d",&t[cnt].d[0],&t[cnt].d[1]);
            LL ww;
            scanf("%lld",&ww);
            t[cnt].w=(1LL<<ww);t[cnt].sum=t[cnt].w;
            t[cnt].max[0]=t[cnt].min[0]=t[cnt].d[0];
            t[cnt].max[1]=t[cnt].min[1]=t[cnt].d[1];
            insert(root,cnt,0);
            if(cnt==lim)
			{
                lim+=9000;
                root=Build(1,cnt,0);
            }
        }
        else if(op==2)
		{
        	X1=1;scanf("%d%d%d",&X2,&Y1,&Y2);
            lans=query(root,X1,Y1,X2,Y2);
            int ans=0;
            for(LL i=0;i<51;i++)
                if(lans&(1LL<<i))
                    ans++;
            printf("%d\n",ans);
        }
        else cnt=0,lim=9000,root=0,memset(t,0,sizeof(t));
    }
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值