现在的位置: 首页 > 综合 > 正文

线段树 区间合并

2019年02月09日 ⁄ 综合 ⁄ 共 1615字 ⁄ 字号 评论关闭

hdu3667:

题意:定义两种操作,询问最大连续的空间,返回首地址;清除以及将一段区间置1。

思路:线段树,定义三个数组分别表示从左,右,中,的最大连续长度,注意向上更新时合并区间的操作。

写了一段时间,错了很多地方。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 55555
using namespace std;
int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2];
int col[maxn<<2];
void PushUp(int rt,int m)
{
    lsum[rt]=lsum[rt<<1];
    rsum[rt]=rsum[rt<<1|1];
    if(lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
    if(rsum[rt]==(m>>1))  rsum[rt]+=rsum[rt<<1];//写错了
    msum[rt]=max(max(msum[rt<<1],msum[rt<<1|1]),rsum[rt<<1]+lsum[rt<<1|1]);//写错了
}
void PushDown(int rt,int m)
{
    if(col[rt]!=-1)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        lsum[rt<<1]=rsum[rt<<1]=msum[rt<<1]=col[rt]?0:m-(m>>1);
        lsum[rt<<1|1]=rsum[rt<<1|1]=msum[rt<<1|1]=col[rt]?0:(m>>1);
        col[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
    lsum[rt]=msum[rt]=rsum[rt]=r-l+1;
    col[rt]=-1;
    if(l==r)
    {
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
int query(int c,int l,int r,int rt)
{
    if(l==r)
    {
        return l;//直到一个点为止
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    if(msum[rt<<1]>=c) return query(c,lson);
    else if(rsum[rt<<1]+lsum[rt<<1|1]>=c) return m-rsum[rt<<1]+1;
    else return query(c,rson);

}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        lsum[rt]=rsum[rt]=msum[rt]=c?0:r-l+1;
        col[rt]=c;
        return ;//第二个错
    }
    PushDown(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m)
    update(L,R,c,lson);
    if(R>m)
    update(L,R,c,rson);
    PushUp(rt,r-l+1);
}
int main()
{
    int n,m,ord,cc,p,a,b;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    for(int i=0;i<m;i++)
    {
        scanf("%d",&ord);
        if(ord==1)
        {
            scanf("%d",&cc);
            if(msum[1]<cc)
            printf("0\n");
            else
            {
                p=query(cc,1,n,1);
                printf("%d\n",p);           //第一个错
                update(p,p+cc-1,1,1,n,1);//1表示覆盖
            }
        }
        else
        {
            scanf("%d%d",&a,&b);
            update(a,a+b-1,0,1,n,1);//0表示清除
            //错误三 区间写错了
        }
    }
	return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.