hdu6183(线段树动态开点)

链接:点击打开链接

题意:有三种操作,分别为:

0 清除矩阵中所有颜色

1 x y c 在(x,y)点涂上c颜色

2 x y1 y2 询问左上角为(1,y1),右上角为(x,y2)的矩阵中含有的颜色种数

代码:

#include <stack>
#include <string>
#include <vector>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int siz=1000005;
int id=0;
int rt[105],ll[siz],rr[siz],val[siz];
void build(int &s,int p,int L,int R,int x){
    if(s==0){                                   //主要就是动态开点,需要时再建立节点
        s=(++id);                               //并不会建一颗完整的线段树
        val[s]=x;                               //剩下的跟静态建线段树是一样的
    }
    if(val[s]>x)
    val[s]=x;
    if(L==R)
    return;
    int m=(L+R)>>1;
    if(p<=m)
    build(ll[s],p,L,m,x);
    else
    build(rr[s],p,m+1,R,x);
}
void query(int p,int L,int R,int l,int r,int x,int &pos){
    if(l<=L&&R<=r){                             //查询时最好也不要遍历整颗树
        if(val[p]<=x)                           //已经小于就不再继续遍历
        pos=1;
        return;
    }
    if(pos)
    return;
    int m=(L+R)>>1;
    if(l<=m&&ll[p]!=0)
    query(ll[p],L,m,l,r,x,pos);
    if(r>m&&rr[p]!=0)
    query(rr[p],m+1,R,l,r,x,pos);               //整体思路就是建50颗线段树
}                                               //按y轴建树,单点更新,求区间最小的x值
int main(){                                     //rt[i]表示i颜色线段树的根节点
    int i,c,x,y1,y2,op,ans,pos;                 //ll[i]表示编号i节点的左儿子
    memset(rt,0,sizeof(rt));                    //rr[i]表示编号i节点的右儿子
    memset(ll,0,sizeof(ll));
    memset(rr,0,sizeof(rr));
    while(scanf("%d",&op)&&op!=3){
        if(op==0){
            for(i=0;i<=50;i++)
            rt[i]=0;
            for(i=0;i<=id;i++)
            ll[i]=rr[i]=0;
            id=0;
        }
        else if(op==1){
            scanf("%d%d%d",&x,&y1,&c);
            build(rt[c],y1,1,1000000,x);
        }
        else if(op==2){
            scanf("%d%d%d",&x,&y1,&y2);
            ans=0;
            for(i=0;i<=50;i++){
                pos=0;
                query(rt[i],1,1000000,y1,y2,x,pos);
                if(pos==1)
                ans++;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值