HDU 4391 Paint The Wall 线段树染色问题

在这里插入图片描述题目大意:给出 n n n面墙的初始颜色, m m m个询问 ( a , l , r , z ) (a,l,r,z) (a,l,r,z),如果 a = 1 a=1 a=1,表示把 [ l , r ] [l,r] [l,r]的所有墙染成 z z z,如果 a = 2 a=2 a=2,表示查询 [ l , r ] [l,r] [l,r]的颜色为 z z z的墙的数量。

思路:线段树比分块哈希快得多……就离谱。修改操作就不多说了,一个 l a z y lazy lazy标记就行了,主要是查询,暴力找肯定不行,我们维护一个区间最大值和区间最小值,判断要查询的颜色是否在这个范围内,这样就可以省去很多时间。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

const int maxn=1e5+5;

struct Tree
{
    int l,r,lazy,MAX,MIN;
}tree[maxn<<2];

int n,m;

inline void up(int i)
{
    int l=i<<1,r=i<<1|1;
    tree[i].MAX=max(tree[l].MAX,tree[r].MAX);
    tree[i].MIN=min(tree[l].MIN,tree[r].MIN);
}

inline void down(int i)
{
    int l=i<<1,r=i<<1|1;
    tree[l].lazy=tree[r].lazy=tree[i].lazy;
    tree[l].MAX=tree[l].MIN=tree[i].lazy;
    tree[r].MAX=tree[r].MIN=tree[i].lazy;
    tree[i].lazy=-1;
}

void build(int i,int l,int r)
{
    tree[i].lazy=-1;
    tree[i].l=l,tree[i].r=r;
    if(l==r)
    {
        scanf("%d",&tree[i].MAX);
        tree[i].MIN=tree[i].MAX;
        return ;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    up(i);
}

void update(int i,int l,int r,int v)
{
    if(tree[i].l==l&&tree[i].r==r)
    {
        tree[i].lazy=v;
        tree[i].MAX=tree[i].MIN=v;
        return ;
    }
    if(tree[i].lazy!=-1)
        down(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        update(i<<1,l,r,v);
    else if(l>mid)
        update(i<<1|1,l,r,v);
    else
        update(i<<1,l,mid,v),update(i<<1|1,mid+1,r,v);
    up(i);
}

int query(int i,int l,int r,int v)
{
    if(tree[i].MAX<v||tree[i].MIN>v)
        return 0;
    if(tree[i].l==l&&tree[i].r==r)
    {
        if(tree[i].lazy!=-1)
        {
            if(tree[i].lazy==v)
                return r-l+1;
            return 0;
        }
        if(l==r)
        {
            if(tree[i].MAX==v)
                return 1;
            return 0;
        }
    }
    if(tree[i].lazy!=-1)
        down(i);
    int mid=(tree[i].l+tree[i].r)>>1;
    if(r<=mid)
        return query(i<<1,l,r,v);
    else if(l>mid)
        return query(i<<1|1,l,r,v);
    else
        return query(i<<1,l,mid,v)+query(i<<1|1,mid+1,r,v);
    up(i);
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        build(1,1,n);
        int op,l,r,v;
        while(m--)
        {
            scanf("%d%d%d%d",&op,&l,&r,&v);
            ++l,++r;
            if(op==1)
                update(1,l,r,v);
            else
                printf("%d\n",query(1,l,r,v));
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值