hdu2795(线段树单点更新)

2014-11-24 02:54:35 · 作者: · 浏览: 1

题目链接:hdu2795

/*线段树单点更新
题目大意:有一块板子,长宽分别为W,H,然后有n块1*w海报
让你把这n快海报贴在这块板子上,尽量往板子的上方贴,同一行尽量往板子的左边贴。
对于第i块海报如果能够贴下则输出能贴在第几行,否则输出-1。

思路:利用线段树求区间的最大值;
maxx表示区间内能贴的海报的最大宽度
建树的时候要注意,heigh的范围特别大
当heigh>=m(m是海报的数量),要用m来建树
*/
#include
  
   
#include
   
     using namespace std; #define N 200005 int n,flag,heigh,wide,num; struct node { int left,right; int maxx; }s[N<<2]; void build(int left, int right, int n) { s[n].left = left; s[n].right = right; s[n].maxx = wide; if(left == right) return ; int mid = (left + right) >> 1; build(left, mid, n<<1); build(mid+1, right, n<<1|1); } void update(int id, int n) { if(s[n].left == id && s[n].right == id) { s[n].maxx -= num; return ; } int mid = (s[n].left + s[n].right) >> 1; if(id <= mid) update(id, n<<1); else if(id > mid) update(id, n<<1|1); s[n].maxx = max(s[n<<1].maxx, s[n<<1|1].maxx); } int query(int left, int right, int n) { if(s[n].maxx < num) return -1; if(s[n].left == s[n].right) return left; int mid = (s[n].left + s[n].right) >> 1; if(s[n<<1].maxx >= num)//先向左子树中查询 return query(left, mid, n<<1); else return query(mid+1, right, n<<1|1); } int main() { int i,m; while(~scanf("%d%d%d",&heigh,&wide,&m)) { m>=heigh   build(1,heigh,1):build(1,m,1);//建树时要注意 while(m--) { scanf("%d",&num); int ans = query(1,heigh,1); if(ans == -1) printf("-1\n"); else { printf("%d\n",ans); update(ans,1); } } } return 0; }