poj 1823 Hotel (分段线段树)

很长时间没写过分段的线段树了,自己开始一看也感觉一头雾水,但是最长的长度分为左最长,最长和右最长这是一开始就必须清楚的,分段更新我也不太熟悉,看了下别人的博客,感觉思路很清晰,敲出来,最后2个数据怎么搞都是错的,整整改了2个小时,最后看着别人的代码一句一句的对着看,终于发现自己看掉了一种情况,记事在左右结点的状态改变后,父节点也需要按条件进行改变。也就是upDate中的

if(node[L(u)].f == node[R(u)].f)
        node[u].f = node[R(u)].f;

#include<cstdio>
#include<cstring>
#include<iostream>
#define L(u) (u<<1)
#define R(u) (u<<1|1)
using namespace std;
const int N = 16010;

struct Node {
int l,r;
int lma, ma, rma, f;
}node[N<<2];

int Max(int a,int b)
{
    return a>b?a:b;
}

void pushDown(int u,int c)//往下一层进行更新操作
{
    node[u].f = 0;
    node[L(u)].f = c;
    node[R(u)].f = c;  //左右继续保持原状,便于继续进行更新
    if(c == 1)
    {
        node[L(u)].lma = node[L(u)].ma = node[L(u)].rma = 0;
        node[R(u)].lma = node[R(u)].ma = node[R(u)].rma = 0;

    }
    else
    {
        node[L(u)].lma = node[L(u)].ma = node[L(u)].rma = node[L(u)].r - node[L(u)].l + 1;
        node[R(u)].lma = node[R(u)].ma = node[R(u)].rma = node[R(u)].r - node[R(u)].l + 1;
    }

}

void build(int u,int left,int right)
{
    node[u].l = left, node[u].r = right;
    if(node[u].l==node[u].r)
    {
        return;
    }
    int mid = (node[u].l+node[u].r)>>1;
    build(L(u),left,mid);
    build(R(u),mid+1,right);
}

void upDate(int u,int left,int right,int c)
{
   if(left<=node[u].l&&node[u].r<=right)
   {
       node[u].f = c;
       if(c == 1)
       {
           node[u].lma = node[u].ma = node[u].rma = 0;
       }
       else
       {
            node[u].lma = node[u].ma = node[u].rma = node[u].r - node[u].l + 1;
       }
       return;
   }
   if(c == node[u].f)
   return;

   if(-1*c == node[u].f)
   {
       pushDown(u, node[u].f);
   }

   int mid = (node[u].l+node[u].r)>>1;

   if(right<=mid)
    upDate(L(u),left,right,c);
   else if(left>mid)
    upDate(R(u),left,right,c);
   else
    {
    upDate(L(u),left,mid,c);
    upDate(R(u),mid+1,right,c);
    }

    //这里需要对父节点的信息进行更新
    if(node[L(u)].f == -1)
    {
        node[u].lma = node[L(u)].ma + node[R(u)].lma;
    }
    else
    {
        node[u].lma = node[L(u)].lma;
    }

    if(node[R(u)].f == -1)
    {
        node[u].rma = node[R(u)].ma + node[L(u)].rma;
    }
    else
    {
        node[u].rma = node[R(u)].rma;
    }

    int a = node[L(u)].rma + node[R(u)].lma;
    int b = Max(node[L(u)].ma, node[R(u)].ma);
    int g = Max(node[u].lma, node[u].rma);
    node[u].ma = Max(Max(a,b),g);

    if(node[L(u)].f == node[R(u)].f)
        node[u].f = node[R(u)].f;
}

int main(void)
{
    int n, m, x, y, z;
    scanf("%d%d",&n,&m);
    build(1, 1, n);
    node[1].f = -1;
    node[1].ma = n;
    while(m--)
    {
        scanf("%d",&x);
        if(x == 1)
        {
        scanf("%d%d",&y,&z);
        upDate(1, y, y+z-1, 1);
        }
        else if(x == 2)
        {
        scanf("%d%d",&y,&z);
        upDate(1, y, y+z-1, -1);
        }
        else
        {
            cout<<node[1].ma<<endl;
        }
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值