1. 程式人生 > >2795 線段樹點修改,求區間最大

2795 線段樹點修改,求區間最大

題意

給你一個廣告牌的長度和寬度,和要貼的廣告數。每條廣告的長度為 1 ,輸入n條廣告的高。輸出廣告所在的行數。所有的廣告都靠左貼。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=524288+10;
int node[maxn];   // 存放區間最大值(最寬的哪一行)
int h,w,n;
void bulid(int l,int r,int rt)     
{
    node[rt]=w;  // 把每一個區間初始化為 剩餘的寬度,一開始沒貼廣告所以每個區間剩餘寬度等於廣告牌的寬
    if(l==r)
        return ;
    int m=(l+r)>>1;
    bulid(l,m,rt<<1);
    bulid(m+1,r,rt<<1|1);
}
int query(int x,int l,int r,int rt)
{
    if(l==r)   // 廣告只能貼在葉子結點區間上   每一個葉子結點代表一行
    {
        node[rt]-=x;
        return l;  // 這個廣告貼在第幾行(葉子節點)
    }
    int m=(l+r)>>1;
    int res;
    if(node[rt<<1]>=x)    // 如果左子樹的 剩餘最大寬度 大於需要的寬度就遍歷左子樹,否則就遍歷右子樹         
                           //正好符合先貼左邊的要求 
        res=query(x,l,m,rt<<1);
    else
        res=query(x,m+1,r,rt<<1|1);
    node[rt]=max(node[rt<<1],node[rt<<1|1]);  // 更新剩餘最大寬度
    return res;
}
int main()
{

    int x;
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        if(h>n)
            h=n;  //最多輸入n行資料,當h>n時,建n行就夠了
        bulid(1,h,1);   // 以位置h建樹 
        for(int i=0;i<n;i++)
        {
            scanf("%d",&x);
            if(x>node[1])  //node[1]為所有區間當中的最大值
                printf("-1\n");
            else
                printf("%d\n",query(x,1,h,1));
        }
    }
    return 0;
}

這道題如果不是掛在線段樹專題,我肯定不會想到用線段樹。。。