HDU 1540(线段树区间合并+维护连续0或1)

题意:1-n个地道,m个次操作,D代表摧毁第i个地道,Q代表查询包含第i个地道的最大连续地道数目,并输出。R代表修复最近摧毁的那个地道;

思路:这题利用了线段树的相邻结点区间是连续的特性,而且是维护连续的1,所以用llen、rlen、len数组分别表代表当前结点的1的最长连续前缀长、最长连续后缀长,最长连续区间长,对于某个结点,它的最长连续前缀等于它的左子结点的最长连续前缀,如果它的左子结点的最长连续前缀包含了整个左子区间,那么这个结点的最长连续前缀还要加上右子结点的最长连续前缀;同理,对于某个结点的最长连续后缀是一样的,这里不赘述。而对于某个结点的最长连续区间应该是它的最长连续前缀、最长连续后缀、它的左子结点的最长连续后缀+右子结点的最长连续前缀 三者中的最大值,所以pushUp函数就可以写出来了。建树和更新的时候直接在l==r的时候赋值即可。对于查询,代码注释已经给出,画一下图很好理解的。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn=50005;
const int mod=1e9+7;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int len[maxn<<2],llen[maxn<<2],rlen[maxn<<2];
void pushUp(int rt,int length)
{
    llen[rt]=llen[rt<<1]; //当前结点的最长连续前缀=左子结点的最长连续前缀
    rlen[rt]=rlen[rt<<1|1];
    if(llen[rt<<1]==(length-(length>>1)))   llen[rt]+=llen[rt<<1|1];
    //如果左子结点的最长连续前缀为整个左子区间,那么本结点的前缀还要加上右子区间的最长前缀
    if(rlen[rt<<1|1]==(length>>1))   rlen[rt]+=rlen[rt<<1];
    len[rt]=max(max(len[rt<<1],len[rt<<1|1]),rlen[rt<<1]+llen[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        len[rt]=llen[rt]=rlen[rt]=1;
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushUp(rt,r-l+1);
}
void update(int loc,int C,int l,int r,int rt)
{
    if(l==r)
    {
        len[rt]=llen[rt]=rlen[rt]=C;
        return ;
    }
    int m=(l+r)>>1;
    if(loc<=m)  update(loc,C,l,m,rt<<1);
    if(loc>m) update(loc,C,m+1,r,rt<<1|1);
    pushUp(rt,r-l+1);
}
int query(int loc,int l,int r,int rt)
{
    if(l==r)    return len[rt];
    int m=(l+r)>>1;
    if(loc<=m)
    {
        if(loc+rlen[rt<<1]>m)   return rlen[rt<<1]+llen[rt<<1|1];
        //如果loc在左子区间的最长后缀和右子区间的最长前缀中,直接输出这两个前后缀之和即可
        else return query(loc,l,m,rt<<1);
        //否则的话,继续向左子节点查询
    }
    else
    {
        if(m+llen[rt<<1|1]>=loc)    return rlen[rt<<1]+llen[rt<<1|1];
        //因为右子区间是(mid,r]左开区间,所以这里判断loc是否在右子区间的前缀的范围内用的是 ">="
        else return query(loc,m+1,r,rt<<1|1);
    }
}
int main()
{
    std::ios::sync_with_stdio(false);
    int n,m;
    while(cin>>n>>m)
    {
        build(1,n,1);
        int tot=0,stk[maxn];
        while(m--)
        {
            char c;
            cin>>c;
            if(c=='D')
            {
                int loc;
                cin>>loc;
                stk[++tot]=loc;
                update(loc,0,1,n,1);
            }
            else if(c=='R')
            {
                int loc=stk[tot--];
                update(loc,1,1,n,1);

            }
            else
            {
                int loc;
                cin>>loc;
                cout<<query(loc,1,n,1)<<endl;
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Dilly__dally/article/details/84747514