hdu 2795--简单线段树

题意: 有一个黑板 高h,宽w。 1<=h,w<=10^9 ,现在要贴n个广告上去 n<200000,每一个广告高都是1,然后会输入每一个广告的宽度。 广告会尽量的往上往右贴,贴广告的order按输入的顺序,没输入一个广告求贴在第几行。

这题想了大概有30分钟,一开始想h和w 太大了,根本开不了数组,就更不用提建树了。后来发现就每一个广告单独贴一行也只需要200000行,所以如果可以 以行来建立线段树。 如果h>n 那么以h 否则以n (建树)!
然后又仔细想了想,用val 来表示某区间可容纳的最大的长度。都初始化为w(宽度),然后对于每一个广告,我们写在查询里面,于是这题 应该是可以写粗来的-。- 详细的东西就写在代码里面了。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define pfn printf("\n")
#define sf  scanf
#define pf  printf
#define fr(i,n) for(int i=0;i<n;i++)
#define INF 0x7fffffff   //INT_MAX
#define inf 0x3f3f3f3f   //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
using namespace std;
const int MAXN = 200005;
struct node{
    int l,r;
    //int lazy;  
    int val;  //l-r行可以存的最大空间
}segTree[MAXN*4];
int h,w;
void build(int L,int R,int n){
    segTree[n].l=L;
    segTree[n].r=R;
//    segTree[n].lazy=0;
    segTree[n].val=w;
    if(L==R)
        return;
    int mid=(L+R)/2;
    build(L,mid,2*n);
    build(mid+1,R,2*n+1);
}
void push_up(int n){   //刚开始没有写这个函数,这里是需要向上更新的,这个错误检查到修改 弄半个小时
    int flag;
    if(n==0)
        return;
    flag=max(segTree[n<<1].val,segTree[(n<<1)|1].val);
    if(segTree[n].val > flag){
        segTree[n].val=flag;
        return push_up(n/2);  //写了这个其实是有点怕超时的,然而好像不会有很大的影响。
    }
    else
        return;
    if(n==1)
        return;
}
void push_down(int n){
    segTree[n].val=max(segTree[n<<1].val,segTree[(n<<1)|1].val);
}

//void update(int l,int r,int n,int ll){
//    if(segTree[n].l==l && segTree[n].r==r){
//      segTree[n].lazy=1;
//      segTree[n].val-=ll;
//      return;
//    }
//    push_up(n);
//    int mid=(segTree[n].l + segTree[n].r)/2;
//    if(r<=mid) update(l,r,n<<1,ll);
//    else if(l>mid) update(l,r,(n<<1)|1,ll);
//    else{
//        update(l,mid,n<<1,ll);
//        update(mid+1,r,(n<<1)|1,ll);
//    }
//}
int query(int i,int u){
    if(u>segTree[i].val)      //刚开始写在下面了,减去一遍再比较,这不是sb吗? 
        return -1;
    if(segTree[i].val>=u && segTree[i].l==segTree[i].r){
        segTree[i].val-=u;
        push_up(i/2);     //修改了线段树中的某一个节点的剩余值后朝上更新。
        return segTree[i].l;
    }
    if(u<=segTree[i<<1].val) return query(i<<1,u);   //如果可以向左,先向左,因为更靠近上面的行
    else return query((i<<1)|1,u);
}
int main()
{
    int t;
    //freopen("1.txt","r",stdin);
    while(~scanf("%d %d %d",&h,&w,&t)){
        if(t<=h) build(1,t,1);
        else build(1,h,1);
        for(int num=1;num<=t;num++){
            int w;
            scanf("%d",&w);
            printf("%d\n",query(1,w));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值