hdu 2795 billboard(线段树)

来源:互联网 发布:老是找不到东西知乎 编辑:程序博客网 时间:2024/04/30 09:18

把公告牌的每一行看作线段树的叶节点,因为n的范围是小于等于200000,所以加入每个成员都占用一行,那也做多用200000行,所以构造一个线段树,叶子结点保存的是目前所能用的宽度,然后其余节点保存的是左右节点的最大值,则祖先节点保存的是所有叶节点中值最大的那个。 然后对于每个数据,先跟祖先节点比,如果比他大,则输出-1,表示这个成员的宽度在每一行都容纳不了。否则,则优先从左子树查找,因为每个广告都想往最前面最左边放,当查找到符合的叶子结点后,返回他的L值(L=R),即为这个数据所求的答案。代码如下:

 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; int tree[840000],h,w,n; void build(int i,int l,int r) {     tree[i]=w;     if(l==r)        return;     build(i*2,l,(l+r)/2);     build(i*2+1,(l+r)/2+1,r); } int query(int i,int l,int r,int x) {     if(l==r)     {         tree[i]-=x; //当找到合适的结点,更新         return l;     }     int res=(tree[i*2]>=x)?query(i*2,l,(l+r)/2,x):query(i*2+1,(l+r)/2+1,r,x);//优先找左子树     tree[i]=max(tree[i*2],tree[i*2+1]);  //回溯时更新每个节点的值     return res; } int main() {     int x;     while(scanf("%d%d%d",&h,&w,&n)!=EOF)     {         if(h>n)         {             h=n;         }         memset(tree,0,sizeof(tree));         build(1,1,h);         while(n--)         {             scanf("%d",&x);             if(x>tree[1]) //a[1]始终保持着所有行里的最大值             {                 printf("-1\n");             }             else             {                 printf("%d\n",query(1,1,h,x));             }         }     }     return 0; }


0 0
原创粉丝点击