40 线段树(单点更新)

B - Billboard

Problem B. Billboard Input file: billboard.in Output file: billboard.out Time limit: 3 seconds Memory limit: 256 megabytes
At the entrance to the university, there is a huge rectangular billboard of size h×w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information. On September 1, the billboard was empty. One by one, the announcements started being put on the billboard. Each announcement is a stripe of paper of unit height. More specifically, the i-th announcement is a rectangle of size 1 × wi. When someone puts a new announcement on the billboard, she would always choose the topmost possible position for the announcement. Among all possible topmost positions she would always choose the leftmost one. If there is no valid location for a new announcement, it is not put on the billboard (that’s why some programming contests have no participants from this university). Given the sizes of the billboard and the announcements, your task is to find the numbers of rows in which the announcements are placed.
Input The first line of the input file contains three integer numbers, h, w, and n (1 ≤ h,w ≤ 109; 1 ≤ n ≤ 200000) — the dimensions of the billboard and the number of announcements. Each of the next n lines contains an integer number wi (1 ≤ wi ≤ 109) — the width of i-th announcement.
Output
For each announcement (in the order they are given in the input file) output one number — the number of the row in which this announcement is placed. Rows are numbered from 1 to h, starting with the top row. If an announcement can’t be put on the billboard, output “-1” for this announcement.
Example

这道题目的提议很好理解就是放东西,如果一行能放的下就放在最靠左的地方,如果是有多行能放的下放在最上面的地方,如果放不下了就输出-1,如果是能放下的话,就输出我们把它放在了哪一行;

这道题目当时在看到的时候感觉跟网络赛的那一道题目,差不多这里n很小,从n下手,每次查找是log的,修改是log的就解决了,但是当时用的是set,,,,我不知道,这里的结构体能不能用set的排序,和二分,这个思路来就抛弃了,之后根本没有想过用线段树,因为之前的时候线段树解决的是区间问题,这道题目不是,并且还要我们输出下标,还要从输出最小的下标,其实当时就是没有多想,自己如果是在多想一点的话这道题目就a了,其实线段树正好是这个思想,找到大于等于这个数字的最小下标的一个数字(叶子节点)因为我们是从小到大查找的所以这里找到的下标就是我们要的;注意还要修改;

#include <bits/stdc++.h>
using namespace std;

const int Max = 1e6+10;
typedef long long ll;
struct node {
      ll sum,l,r;
}tr[Max];
ll h,w,n;
void push(int root){
   tr[root].sum=max(tr[root<<1].sum,tr[root<<1|1].sum);
}

void build(int root, int l, int r){
    tr[root].l=l;
    tr[root].r=r;
    if(l==r) {
      tr[root].sum=w;
      return ;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    push(root);
}
int x;
int query(int root , int l, int r){
    if(x>tr[root].sum)  return -1;
    if(l==r){
      tr[root].sum-=x;
      return l;
      push(root);
    }
    int pos=-1;
    int mid=(l+r)>>1;
    if(tr[root<<1].sum>=x)  pos = query(root<<1,l,mid);
    push(root);
    if(pos!=-1) return  pos;
    if(tr[root<<1|1].sum>=x) pos = query(root<<1|1,mid+1,r);
    push(root);
    return pos;
}
int main(){
   freopen("billboard.in","r",stdin);
   freopen("billboard.out","w",stdout);
   scanf("%lld %lld %lld",&h,&w,&n);
   h=min(n,h);
   build(1,1,h);
   for(int i=1;i<=n;i++){
     scanf("%d",&x);
     if(x>tr[1].sum) printf("-1\n");
     else printf("%d\n",query(1,1,h));
   }
   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39792342/article/details/82949452
40