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

POJ 3667 線段樹 + 延遲標記 + 區間處理

編輯:C++入門知識

[cpp]   /*    貼個神牛的代碼,自己寫的代碼難看的別提有多惡心了 ...    類型:線段樹 + 延遲標記 + 區間合並...     */   #include<iostream>   #include<cstring>   #include<cctype>   #include<cstdio>   #include<algorithm>   using namespace std;   #define L(r) r<<1   #define R(r) r<<1|1   const int MAXM=50005;   typedef struct   {       int lsum,rsum,msum;//分別表示左邊最大房間數,右邊最大房間數,整體最大房間數       int cover;//是否住下   }node;   node tree[MAXM<<2];   void pushDown(int root,int m)//向下更新   {    www.2cto.com     if(tree[root].cover==-1) return;//是否已經更新       tree[L(root)].cover=tree[R(root)].cover=tree[root].cover;       tree[L(root)].msum=tree[L(root)].lsum=tree[L(root)].rsum=tree[root].cover?0:m-(m>>1);       tree[R(root)].msum=tree[R(root)].lsum=tree[R(root)].rsum=tree[root].cover?0:(m>>1);       tree[root].cover=-1;   }   void pushUp(int root,int m)//向上更新   {       tree[root].lsum=tree[L(root)].lsum;       tree[root].rsum=tree[R(root)].rsum;       if(tree[root].lsum==m-(m>>1) ) tree[root].lsum+=tree[R(root)].lsum;  // 區間合並        if(tree[root].rsum==(m>>1) ) tree[root].rsum+=tree[L(root)].rsum;          tree[root].msum=max(tree[R(root)].lsum+tree[L(root)].rsum,max(tree[L(root)].msum,tree[R(root)].msum) );   }   void Create(int l,int r,int root)//建樹過程   {       tree[root].cover=-1;       tree[root].lsum=tree[root].rsum=tree[root].msum=r-l+1;       if(l==r){return;}       int mid=(l+r)>>1;       Create(l,mid,L(root));       Create(mid+1,r,R(root));   }   void update(int ll,int rr,int c,int l,int r,int root)//更新   {       if(ll<=l&&r<=rr)//如果找到這個范圍就直接賦值返回,不向下繼續更新       {           tree[root].msum=tree[root].lsum=tree[root].rsum=c?0:r-l+1;           tree[root].cover=c;           return;       }       pushDown(root,r-l+1);//用到這個節點的子節點的時候就向下更新       int m=(l+r)>>1;       if(ll<=m) update(ll,rr,c,l,m,L(root));       if(m<rr) update(ll,rr,c,m+1,r,R(root));       pushUp(root,r-l+1);//向下更新完後需要把節點信息反饋給父節點   }   int query(int w,int l,int r,int root)//查詢滿足連續房間數量的最左節點   {       if(l==r) return l;       pushDown(root,r-l+1 );//用到這個節點的子節點的時候就向下更新       int m=(l+r)>>1;       //////////////////// 注意順序, 區間的處理        if(tree[L(root)].msum>=w) return query(w,l,m,L(root));//如果左兒子滿足就詢問左兒子       else if(tree[L(root)].rsum+tree[R(root)].lsum>=w) return m-tree[L(root)].rsum+1;//如果左兒子和右兒子之間的數量滿足,則范圍左兒子右邊連續房間第一個的編號       else return query(w,m+1,r,R(root));//如果兩者都不滿足則詢問右兒子   }   int main()   {       int n,m;       while(~scanf("%d %d",&n,&m))       {           Create(1,n,1);           int a,num,x,d,p;           for(int i=0;i<m;++i)           {               scanf("%d",&a);               if(1==a)               {                   scanf("%d",&num);                   if(tree[1].msum<num) puts("0");//如果整個區間的最大連續房間數量小於預定的數量就輸出0                   else                   {                       p=query(num,1,n,1);//找到最左節點p                       printf("%d\n",p);                       update(p,p+num-1,1,1,n,1);//把已經有人的房間標記一下                   }               }               else               {                   scanf("%d %d",&x,&d);                   update(x,x+d-1,0,1,n,1);//把此范圍的房間標記成無人               }           }       }       return 0;   }  

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