zoukankan      html  css  js  c++  java
  • 【POJ 3667 】 线段树之区间操作

    题目连接:http://poj.org/problem?id=3667

     

    题目大意:让你对一个区间进行操作。输入Q C 或者 Q C D。

    Q ==1  输入 C: 表示让你求1-n中是否有连续的C个空hotel,如果有多个连续的C个空hotel,则取最左边的,并输出最左边的第一间hotel标号。让人住进去,那么这些空房就不能住人了。如果不存在连续的C个hotel,则输出 0。

    Q==2   输入 C D: 表示 从标号C到C+D-1的hotel的房间全部要退房,那么这么hotel都变成空。

     

    解题思路:

    用到线段树的区间操作,具体解析见代码。

      1 #include <cstdio>
      2 #include <cmath>
      3 #include <iostream>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 #define lz 2*u,l,mid
      8 #define rz 2*u+1,mid+1,r
      9 const int maxn=50005;
     10 int  flag[4*maxn];   ///标记
     11 
     12 struct node
     13 {
     14     int lm; ///从左边第一个点开始最长的连续空hotel
     15     int rm; ///以右边最后一个结束的最长的连续空hotel
     16     int sm; ///整段区间最大的连续空hotel 
     17 } tree[4*maxn];
     18 
     19 void push_up(int u, int l, int r)   ///向上更新
     20 {
     21     tree[u].lm=tree[2*u].lm;          
     22     tree[u].rm=tree[2*u+1].rm;
     23     tree[u].sm=max(tree[2*u].sm,tree[2*u+1].sm);
     24     int mid=(l+r)>>1;
     25     if(tree[2*u].lm==mid-l+1) tree[u].lm+=tree[2*u+1].lm;  ///!!这里注意,当左孩子左边连续的达到整个区间时,要加上右孩子的左边区间
     26     if(tree[2*u+1].rm==r-mid) tree[u].rm+=tree[2*u].rm;   ///!!考虑右区间,同上
     27     int t=tree[2*u].rm+tree[2*u+1].lm;
     28     if(t>tree[u].sm) tree[u].sm=t;
     29 }
     30 
     31 void push_down(int u, int l, int r)  ///向下更新
     32 {
     33     if(flag[u]==-1) return ;
     34     if(flag[u])
     35     {
     36         flag[2*u]=flag[2*u+1]=flag[u];
     37         tree[2*u].lm=tree[2*u].rm=tree[2*u].sm=0;
     38         tree[2*u+1].lm=tree[2*u+1].rm=tree[2*u+1].sm=0;
     39         flag[u]=-1;
     40     }
     41     else
     42     {
     43         flag[2*u]=flag[2*u+1]=flag[u];
     44         int mid=(l+r)>>1;
     45         tree[2*u].lm=tree[2*u].rm=tree[2*u].sm=mid-l+1;
     46         tree[2*u+1].lm=tree[2*u+1].rm=tree[2*u+1].sm=r-mid;
     47         flag[u]=-1;
     48     }
     49 }
     50 
     51 void build(int u, int l, int r)  ///建树
     52 {
     53     flag[u]=-1;
     54     if(l==r)
     55     {
     56         tree[u].lm=tree[u].rm=tree[u].sm=1;
     57         return ;
     58     }
     59     int mid=(l+r)>>1;
     60     build(lz);
     61     build(rz);
     62     push_up(u,l,r);
     63 }
     64 
     65 void Update(int u, int l, int r, int tl, int tr, int c)   ///更新操作
     66 {
     67     if(tl<=l&&r<=tr)
     68     {
     69         tree[u].sm=tree[u].lm=tree[u].rm=(c==1?0:r-l+1);
     70         flag[u]= c;  
     71         return ;
     72     }
     73     push_down(u,l,r);   ///再次遇见此段区间时,延迟标记同步向下更新
     74     int mid=(l+r)>>1;
     75     if(tr<=mid) Update(lz,tl,tr,c);
     76     else if(tl>mid) Update(rz,tl,tr,c);
     77     else
     78     {
     79         Update(lz,tl,mid,c);    ///注意区间分隔开,tl,tr跨越两个左右区间
     80         Update(rz,mid+1,tr,c);
     81     }
     82     push_up(u,l,r);     ///递归的时候同步向上更新
     83 }
     84 
     85 int Query(int u, int l, int r, int num)   ///询问操作
     86 {
     87     if(l==r)
     88         return l;
     89     push_down(u,l,r);     ///延迟标记向下传递
     90     int mid=(l+r)>>1;
     91     if(tree[2*u].sm>=num) return Query(lz,num);
     92     else if(tree[2*u].rm+tree[2*u+1].lm>=num&&tree[2*u].rm>=1) return mid-tree[2*u].rm+1;   ///满足条件时,返回左边rm连续的hotel第一个房间标号
     93     else
     94         return Query(rz,num);
     95 }
     96 
     97 int main()
     98 {
     99     int n, m;
    100     while(~scanf("%d%d",&n,&m))
    101     {
    102         build(1,1,n);
    103         while(m--)
    104         {
    105             int p, u, v;
    106             scanf("%d",&p);
    107             if(p==1)
    108             {
    109                 scanf("%d",&u);
    110                 if(tree[1].sm<u)  ///特判一下是否有这么多个连续的空hotel,没有则直接输出,不用操作
    111                 {
    112                     puts("0"); continue;
    113                 }
    114                 int p=Query(1,1,n,u);
    115                 printf("%d\n",p);
    116                 Update(1,1,n,p,p+u-1,1);
    117             }
    118             else
    119             {
    120                 scanf("%d%d",&u,&v);
    121                 Update(1,1,n,u,u+v-1,0);
    122             }
    123         }
    124     }
    125     return 0;
    126 }
  • 相关阅读:
    系统设计5:Google三剑客
    lintcode亚麻九题
    设计模式17:单例模式
    设计模式16:迭代器模式
    设计模式15:组合模式
    476. Number Complement
    561. Array Partition I
    627. Swap Salary
    617. Merge Two Binary Trees
    728. Self Dividing Numbers
  • 原文地址:https://www.cnblogs.com/kane0526/p/2832637.html
Copyright © 2011-2022 走看看