程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> PKU3667(Hotel)線段樹

PKU3667(Hotel)線段樹

編輯:C++入門知識

[cpp]   /**********************************************  題目大意:  有一個旅館,有N個房間排成一排;  現在有兩種操作:  第一是有a個顧客要入住連續的a個房間;  要求輸出最小的左端點的位置,不能滿足就輸出0;  第二是將以a開始,長度為b的連續房間清空;  1  a:  詢問是不是有連續長度為a的空房間,有的話住進最左邊;  2 a b: 將[a,a+b-1]的房間清空;    算法思想:  記錄區間中最長的空房間  lsum表示區間左邊連續的空房個數;  rsum表示區間右邊連續的空房個數;  msum表示區間上最大的一段空房的長度;    算法過程:  如果1~n區間的msum值都比x小,就無解,否則有解;  對於每一個區間,如果它的左兒子的msum值大於等於x,則到左兒子裡去找;  如果左兒子的rsum加上右兒子的lsum大於等於x,則直接返回左兒子的右端點減去左兒子的rsum值;  否則到右兒子裡去找;  ***********************************************/   #include<iostream>   #include<cstring>   #include<cstdlib>   #include<cstdio>   #include<climits>   #include<algorithm>   using namespace std;      #define L  l , m , u << 1   #define R  m + 1 , r , u << 1 | 1      const int N = 55555;   int lsum[N<<2];//區間左邊連續的空房個數;   int rsum[N<<2];//區間右邊連續的空房個數;   int msum[N<<2];//區間上最大的一段空房的長度;      int cover[N<<2];      void PushDown(int u,int m)//把當前結點的信息更新給兒子結點   {       if (cover[u] != -1)       {           cover[u<<1] = cover[u<<1|1] = cover[u];           msum[u<<1] = lsum[u<<1] = rsum[u<<1] = cover[u] ? 0 : m - (m >> 1);           msum[u<<1|1] = lsum[u<<1|1] = rsum[u<<1|1] = cover[u] ? 0 : (m >> 1);           cover[u] = -1;       }   }      void PushUp(int u,int m)//把當前結點的信息更新到父結點   {       lsum[u] = lsum[u<<1];       rsum[u] = rsum[u<<1|1];       if(lsum[u] == m - (m >> 1))           lsum[u] += lsum[u<<1|1];       if(rsum[u] == (m >> 1))           rsum[u] += rsum[u<<1];       msum[u] = max(lsum[u<<1|1] + rsum[u<<1] , max(msum[u<<1] , msum[u<<1|1]));   }      void build(int l,int r,int u)   {       msum[u] = lsum[u] = rsum[u] = r - l + 1;       cover[u] = -1;       if (l == r)           return;       int m = (l + r) >> 1;       build(L);       build(R);   }      void update(int l1,int r1,int c,int l,int r,int u)//區間替換   {       if (l1 <= l && r <= r1)       {           msum[u] = lsum[u] = rsum[u] = c ? 0 : r - l + 1;           cover[u] = c;           return ;       }       PushDown(u , r - l + 1);       int m = (l + r) >> 1;       if (l1 <= m)           update(l1 , r1 , c , L);       if (m < r1)           update(l1 , r1 , c , R);       PushUp(u , r - l + 1);   }      int query(int w,int l,int r,int u)//查詢滿足條件的最左斷點   {       if (l == r)           return l;       PushDown(u , r - l + 1);       int m = (l + r) >> 1;       if (msum[u<<1] >= w)//左兒子的msum值大於等於x,則到左兒子裡去找;           return query(w , L);       else if (rsum[u<<1] + lsum[u<<1|1] >= w)//如果左兒子的rsum加上右兒子的lsum大於等於x,則直接返回左兒子的右端點減去左兒子的rsum值;           return m - rsum[u<<1] + 1;       return query(w , R);//否則到右兒子裡去找;   }      int main()   {       //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);       int n , m;       scanf("%d%d",&n,&m);       build(1 , n , 1);       while (m--)       {           int op , a , b;           scanf("%d",&op);           if (op == 1)           {               scanf("%d",&a);               if (msum[1]<a)                   puts("0");               else               {                   int p = query(a , 1 , n , 1);                   printf("%d\n",p);                   update(p , p + a - 1 , 1 , 1 , n , 1);               }  www.2cto.com         }           else           {               scanf("%d%d",&a,&b);               update(a , a + b - 1 , 0 , 1 , n , 1);           }       }       return 0;   }    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved