poj3667(线段树)

题目连接:http://poj.org/problem?id=3667

题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边

2 a b:将[a,a+b-1]的房间清空

线段树操作:update:区间替换 query:询问满足条件的最左断点

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define M 1000000000
#define maxn 55555
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int lsum[maxn<<2],rsum[maxn<<2],sum[maxn<<2];
int col[maxn<<2];
void PushDown(int rt,int m)
{
    if(col[rt]!=-1)
    {
        col[rt<<1]=col[rt<<1|1]=col[rt];
        sum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=col[rt]?0:m-(m>>1);
        sum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=col[rt]?0:m>>1;
        col[rt]=-1;
    }
}
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];
    sum[rt]=max((lsum[rt<<1|1]+rsum[rt<<1]),max(sum[rt<<1],sum[rt<<1|1]));
}
void build(int l,int r,int rt)
{
    col[rt]=-1;
    sum[rt]=lsum[rt]=rsum[rt]=r-l+1;
    if(l==r)return;
    int m=(r+l)>>1;
    build(lson);
    build(rson);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        sum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1;
        col[rt]=c;
        return;
    }
    PushDown(rt,r-l+1);
    int m=(r+l)>>1;
    if(L<=m)update(L,R,c,lson);
    if(R>m)update(L,R,c,rson);
    PushUp(rt,r-l+1);
}
int query(int w,int l,int r,int rt)
{
    if(l==r)return l;
    PushDown(rt,r-l+1);
    int m=(r+l)>>1;
    if(sum[rt<<1]>=w)return query(w,lson);
    else if(rsum[rt<<1]+lsum[rt<<1|1]>=w)return m-rsum[rt<<1]+1;
    else return query(w,rson);
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)>0)
    {
        build(1,n,1);
        while(m--)
        {
            int a,b,op;
            scanf("%d",&op);
            if(op==1)
            {
                scanf("%d",&a);
                if(sum[1]<a)puts("0");
                else
                {
                    int ans=query(a,1,n,1);
                    printf("%d\n",ans);
                    update(ans,ans+a-1,1,1,n,1);
                }
            }
            else
            {
                scanf("%d%d",&a,&b);
                update(a,a+b-1,0,1,n,1);
            }
        }
    }
}

时间: 2024-10-12 16:36:50

poj3667(线段树)的相关文章

poj3667 线段树 区间合并

1 //Accepted 3728 KB 1079 ms 2 //线段树 区间合并 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <cmath> 8 #include <algorithm> 9 using namespace std; 10 /** 11 * This is a document

POJ-3667 线段树区间合并入门题

题意:长度为n的区间,m个操作,一开始都是0 1 x表示求出长度为x的0的连续区间的最左端,并把这个区间变成1 2 x y表示将区间[x,y]变成0 线段树的区间合并第一题: 每次维护左端连续区间长度ls.右端连续区间长度rs,最大连续长度ms 区间合并的注意点主要在push up操作: 每次更新了一段区间之后向上更新,首先,父区间的ls继承左子树的ls,父区间的rs继承右子树的rs 然后就是重点:左右区间合并之后中间部分可能是连续的!!! 所以:如果整个左.右子区间都是“满的”,父区间的ls和

POJ3667——线段树区间合并(未搞透)——Hotel

The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their v

(线段树) (h) poj3667 (区间合并)

poj3667 Hotel 如在阅读本文时遇到不懂的部分,请在评论区询问,或跳转 线段树总介绍 [题目大意] 有一个旅馆,有N个房间排成一排,现在有两种操作,第一是有X个顾客要入住连续的X个房间, 要求输出最小的左端点的位置,不能满足就输出0,第二是将以L开始,长度为X的连续房间清空. [输入文件] 第一行两个数N,M,表示房间数和操作数 接下来M行,每行有两种情况: 1 X 表示操作1 2 L X 表示操作2 [输出文件] 对于每一个1操作,输出答案. 题即为求最靠左的连续区间并置满以及把一段

poj--3667 Hotel(线段树+区间合并)

Description The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Stree

poj3667【线段树水题】

题意:n个空房间.两种操作:1.选择最小的连续D个房间入住,并输出这连续D个房间的最小标号.2.将某个区间内的房间全部退房. 1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #define ll long long 5 #define lson l, m, rt<<1 6 #define rson m+1, r, rt<<1|1 7 #define st fir

【POJ3667】Hotel(线段树)

题意:有n个依次编号的元素,要求维护以下两个操作: 1.询问整个数列中是否有长度>=x的连续的一段未被标记的元素,若无输出0,若有输出最小的开始编号ans并将[ans,ans+x-1]标记 2.将[x,x+y-1]其中的元素取消标记(如果有) n,m<=5e4 思路:线段树区间合并 记录从左.右边开始最长连续长度,一段最长连续长度,以及标记状态 Pascal跑的比C++快-- 1 #include<cstdio> 2 #include<cstring> 3 #inclu

线段树 区间合并

poj3667 Hotel 区间合并入门题,照着代码打的, 题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边       2 a b:将[a,a+b-1]的房间清空思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数..线段树操作:update:区间替换 query:询问满足条件的最左端点 1 #include<iostream>

约会安排---hdu4553(线段树,麻烦的区间覆盖)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 算是poj3667的加强版,建立两颗线段树,一个是DS区间,另一个是NS区间.那么根据题意,如果是DS的请求,那么首先查找DS的区间,如果有满足的区间就更新DS区间,NS的区间不需要更新.如果是NS的请求,首先看DS区间是否有满足的区间,否则查找NS区间,如果有就同时更新DS区间和NS区间.那么可以归纳为,只要是NS的请求,就同时更新两颗线段树,否则只更新DS的线段树. 注意输出要从Outpu