程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ3667[線段樹、最大連續區間]

POJ3667[線段樹、最大連續區間]

編輯:C++入門知識

線段樹暫時最後一題了吧,線段樹果然可以做的很多很多,和DP結合起來對自己的要求更高了。 自己要做的還差很遠~   這題調試了好長時間。。。  題意:1a:詢問是不是有連續長度為a的空房間,有的話住進最左邊           2a b:將[a,a+b-1]的房間清空           思路:記錄區間中最長的空房間          線段樹操作:update:區間替換query:詢問滿足條件的最左斷點   主要難點在於  void pushup(int rt,int m) {     lsum[rt]=lsum[rt<<1];     rsum[rt]=rsum[rt<<1|1]; //這幾步的處理!     if(lsum[rt]==(m-m/2))         lsum[rt]+=lsum[rt<<1|1];     if(rsum[rt]==m/2)         rsum[rt]+=rsum[rt<<1];     msum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],max(msum[rt<<1],msum[rt<<1|1])); }   理解了就好了~   順便自己對pushdown又錯了一次,pushdown是傳給子孫結點的。    

#include <iostream>  
#include <cstdio>  
#include <cstring>  
  
using namespace std;  
  
#define lson rt<<1,l,m  
#define rson rt<<1|1,m+1,r  
  
const int maxn=50005;  
//經典做法 //msum最大一段連續區間 lsum,rsum從左,右邊起最大連續區間  
int cover[maxn<<8],msum[maxn<<8],lsum[maxn<<8],rsum[maxn<<8];  
  
  
void build(int rt,int l,int r)  
{  
    cover[rt]=-1;  
    msum[rt]=lsum[rt]=rsum[rt]=r-l+1;  
    if(l==r) return;  
    int m=(l+r)>>1;  
    build(lson);  
    build(rson);  
}  
void pushdown(int rt,int m) {  
    if (cover[rt] != -1) {  
        cover[rt<<1] = cover[rt<<1|1] = cover[rt];  
        msum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : m - (m >> 1);  
        msum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : (m >> 1);  
        cover[rt] = -1;  
    }  
}  
void pushup(int rt,int m)  
{  
    lsum[rt]=lsum[rt<<1];  
    rsum[rt]=rsum[rt<<1|1]; //這幾步的處理!  
    if(lsum[rt]==(m-m/2))  
        lsum[rt]+=lsum[rt<<1|1];  
    if(rsum[rt]==m/2)  
        rsum[rt]+=rsum[rt<<1];  
    msum[rt]=max(rsum[rt<<1]+lsum[rt<<1|1],max(msum[rt<<1],msum[rt<<1|1]));  
}  
void update(int ql,int qr,int ch,int rt,int l,int r)  
{  
    if(ql<=l&&qr>=r)  
    {  
        cover[rt]=ch;  
        if(ch==0)  
          msum[rt]=lsum[rt]=rsum[rt]=r-l+1;  
        else if(ch==1)  
          msum[rt]=lsum[rt]=rsum[rt]=0;  
        return;  
    }  
  
    pushdown(rt,r-l+1);  
  
    int m=(l+r)>>1;  
    if(ql<=m)  
        update(ql,qr,ch,lson);  
    if(qr>m)  
        update(ql,qr,ch,rson);  
  
    pushup(rt,r-l+1);  
}  
int query(int ch,int rt,int l,int r)  
{  
    //要返回的是左坐標  
    if(l==r) return l;  
    //呵呵。。。  
    pushdown(rt,r-l+1);  
    int m=(l+r)>>1;  
    if(msum[rt<<1]>=ch)  
        return query(ch,lson);  
    else if((rsum[rt<<1]+lsum[rt<<1|1])>=ch)  
        return m-rsum[rt<<1]+1; //這一步return最為經典  
    else  
        return query(ch,rson);  
}  
  
int main()  
{  
    int n,m,a,b,c;  
    while(scanf("%d%d",&n,&m)!=EOF)  
    {  
        build(1,1,n);  
        for(int i=1;i<=m;i++)  
        {  
            scanf("%d",&a);  
            if(a==1)  
            {  
                scanf("%d",&b);  
                if(msum[1]<b) //利用根結點判斷是否有大於b的  
                    printf("0\n");  
                else  
                {  
                    int pos=query(b,1,1,n);  
                    printf("%d\n",pos);  
                    update(pos,pos+b-1,1,1,1,n);  
                }  
            }  
            else  
            {  
                scanf("%d%d",&b,&c);  
                update(b,b+c-1,0,1,1,n);  
            }  
        }  
    }  
    return 0;  
}  

 


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved