【HDU-6183-Color it】 动态开点的线段树

18 篇文章 0 订阅
4 篇文章 0 订阅

题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=6183
题意
给 你 一 个 二 维 平 面 , 最 开 始 平 面 上 没 有 任 何 点 , 有 4 种 操 作 , 给你一个二维平面,最开始平面上没有任何点,有4种操作, 4
第 一 种 操 作 是   0   表 示 清 除 这 个 平 面 上 所 有 的 点 第一种操作是 \ 0 \ 表示清除这个平面上所有的点  0 
第 二 种 操 作 是 1   x   y   c 表 示 在 ( x , y ) 上 添 加 一 个 颜 色 为 c 的 点 第二种操作是1\ x \ y\ c 表示在(x,y)上添加一个颜色为c的点 1 x y c(x,y)c
第 三 种 操 作 是 2   x   y 1   y 2 查 询 ( 1 , y 1 ) , ( x , y 2 ) 之 间 有 多 少 种 颜 色 第三种操作是2\ x \ y_1 \ y_2 查询(1,y1),(x,y2)之间有多少种颜色 2 x y1 y2(1,y1),(x,y2)
第 四 种 操 作 是 3   表 示 直 接 退 出 程 序 第四种操作是3\ 表示直接退出程序 3 退
下 标 范 围 1 0 6 , 最 多 有 50 种 颜 色 下标范围10^6,最多有50种颜色 106,50
1 , 2 操 作 最 多 1.5 ∗ 1 0 5 次 1,2操作最多1.5*10^5次 121.5105
做法
我 们 想 想 只 有 一 种 颜 色 怎 么 办 , 由 于 左 界 限 已 经 固 定 我们想想只有一种颜色怎么办,由于左界限已经固定
这 就 意 味 着 我 们 可 以 对 y 建 立 权 值 线 段 树 这就意味着我们可以对y建立权值线段树 y线
更 新 操 作 只 要 保 留 每 个 y 位 置 最 小 的 x 就 可 以 更新操作只要保留每个y位置最小的x就可以 yx
这 样 查 询 的 时 候 只 要 看 这 个 颜 色 在 ( y 1 , y 2 ) 这 个 区 间 的 最 小 值 是 不 是 小 于 x 这样查询的时候只要看这个颜色在(y1,y2)这个区间的最小值是不是小于x (y1,y2)x
小 于 则 代 表 这 个 颜 色 在 这 个 范 围 内 出 现 过 小于则代表这个颜色在这个范围内出现过
但 是 本 题 有 50 种 颜 色 , 这 就 意 味 着 我 们 可 以 建 50 颗 线 段 树 分 别 计 算 但是本题有50种颜色,这就意味着我们可以建50颗线段树分别计算 5050线
但 是 这 个 数 据 范 围 明 显 会 M L E , 这 时 候 我 们 就 需 要 动 态 开 点 的 线 段 树 但是这个数据范围明显会MLE,这时候我们就需要动态开点的线段树 MLE线
每 次 更 新 一 条 链 上 的 信 息 , 返 回 这 个 颜 色 对 应 的 新 的 根 节 点 下 标 每次更新一条链上的信息,返回这个颜色对应的新的根节点下标
这 样 每 次 更 新 操 作 只 会 产 生 l o g 个 新 节 点 , 就 没 有 M L E 的 问 题 这样每次更新操作只会产生log个新节点,就没有MLE的问题 logMLE
注 意 一 定 要 先 继 承 之 前 的 信 息 , 再 更 新 本 次 更 新 的 信 息 , 保 证 之 前 的 信 息 被 继 承 下 来 。 注意一定要先继承之前的信息,再更新本次更新的信息,保证之前的信息被继承下来。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6+10;
int tot,minn[maxn*4],lson[maxn*4],rson[maxn*4],root[55];
void init()
{
    tot=0;
    memset(minn,INF,sizeof(minn));
    memset(lson,0,sizeof(lson));
    memset(rson,0,sizeof(rson));
    memset(root,0,sizeof(root));
}
void update(int &now,int l,int r,int pos,int val)
{
    if(!now)
    {
        now=++tot;
        minn[now]=val;
    }
    if(l==r)
    {
        minn[now]=min(minn[now],val);
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(lson[now],l,mid,pos,val);
    else update(rson[now],mid+1,r,pos,val);
    minn[now]=min(minn[lson[now]],minn[rson[now]]);
    return ;
}
int query(int now,int ql,int qr,int l,int r,int maxx)
{
    if(!now) return 0;
    if(ql<=l&&qr>=r)
    {
        if(minn[now]<=maxx) return 1;
        else return 0;
    }
    int mid=l+r>>1;
    int ans=0;
    if(ql<=mid) ans=query(lson[now],ql,qr,l,mid,maxx);
    if(ans>0) return 1;
    if(qr>mid) ans=query(rson[now],ql,qr,mid+1,r,maxx);
    if(ans>0) return 1;
    else return 0;
}
int main()
{
    int op,x,y,c,y1,y2;
    while(scanf("%d",&op)!=EOF)
    {
        if(op==0)
        {
            init();
        }
        else if(op==1)
        {
            scanf("%d%d%d",&x,&y,&c);
            update(root[c],1,1000000,y,x);
        }
        else if(op==2)
        {
            scanf("%d%d%d",&x,&y1,&y2);
            int ans=0;
            for(int i=0;i<=50;i++)
            {
                ans+=query(root[i],y1,y2,1,1000000,x);
            }
            printf("%d\n",ans);
        }
        else
        {
            break;
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值