由於第一周上課聽的的實在太水了,課的難度比我想象的難得多,結果這兩周都在補課呢.............題就做的少了點,主要還是線段樹,寫了一道樹鏈剖分,但掛了,智商拙計啊。
還是說說這周做的印象比較深的題吧:
NO.1 POJ 2528 mayor‘s poster
說實話這題不難,自己寫的也挺快。但確實,沒有動腦子。我是線上段上加一個標誌域c,由c來判斷該地區是否有多種顏色,或者是否全由一種顏色覆蓋;
在最後覆蓋完成之後,再去查詢,這些線段樹上有多少種顏色。
當然這是我的想法,簡直圖樣圖森破。其實可以反響處理,因為後面的海報肯定不會被前面的海報覆蓋。那麼我們從最後一個海報開始,如果能有一些片段能被覆蓋,那麼能看到的海報數就+1,這樣線段樹上也只要維護該地區是否被完全覆蓋,是否不完全被覆蓋,即可,根本不存在顏色問題;
NO.2 POJ3667 Hotel
這題也是線段樹,線上段樹上維護這樣一個值len,llen,rlen,len代表的是這段上最長的連續的空房間的個數,llen表示這個區間最左邊最長連續空房間的個數,rlen表示右邊;在查詢的時候,如果改線段的左半部分的len滿足要求,那麼查詢該左半部分。如果左半地區不滿足,就查詢中間地區(左半部分的rlen+右半部分llen);中間地區不行就查詢右地區,這樣既可;
#include<stdio.h>#include<string.h>#include<algorithm>#define dp node &p=tree[root]#define dlc node &lc=tree[p.lc]#define drc node &rc=tree[p.rc]#define dmid int mid=(p.left+p.right)>>1using namespace std;int tot,n;struct node{int left,right,len;int lc,rc;int ll,rl,ml;int f;}tree[100010];void fresh(int root){dp;p.ll=p.rl=p.ml=p.len;p.f=0;}void fill(int root){dp;p.ll=p.rl=p.ml=0;p.f=1;}void build(int root,int l,int r){dp;p.left=l;p.right=r;p.lc=p.rc=0;p.len=p.right-p.left+1;fresh(root);p.f=-1;if(l==r) return;int mid=(l+r)>>1;build(p.lc=++tot,l,mid);build(p.rc=++tot,mid+1,r);}void down(int root){dp;if(p.f==0){p.f=-1;if(p.lc) fresh(p.lc);if(p.rc) fresh(p.rc);}else if(p.f==1){p.f=-1;if(p.lc) fill(p.lc);if(p.rc) fill(p.rc);}}void up(int root){dp;dlc;drc;int val[3];p.ll=(lc.ll==lc.len?lc.ll+rc.ll:lc.ll);p.rl=(rc.rl==rc.len?rc.rl+lc.rl:rc.rl);val[0]=lc.ml;val[1]=rc.ml;val[2]=lc.rl+rc.ll;p.ml=0;for(int i=0;i<3;++i) p.ml=max(p.ml,val[i]);}void insert(int root,int l,int r){dp;dlc;drc;down(root);if(p.left==l&&p.right==r){fill(root);return;}dmid;if(mid>=r) insert(p.lc,l,r);else if(mid<l) insert(p.rc,l,r);else {insert(p.lc,l,mid);insert(p.rc,mid+1,r);}up(root);}int request(int root,int d){dp;dlc;drc;int res;down(root);if(p.ml<d) res=0;else {if(lc.ml>=d) res=request(p.lc,d); else if(lc.rl+rc.ll>=d) { res=rc.left-lc.rl; d-=lc.rl; if(lc.rl) insert(p.lc,lc.right-lc.rl+1,lc.right); insert(p.rc,rc.left,rc.left+d-1); } else res=request(p.rc,d);}if(p.left!=p.right) up(root); return res;}void del(int root,int l,int r){dp;dlc;drc;if(p.f==0) return;down(root);if(p.left==l&&p.right==r){fresh(root);return;}int mid=(p.left+p.right)>>1;if(mid>=r) del(p.lc,l,r); else if(mid<l) del(p.rc,l,r); else del(p.lc,l,mid),del(p.rc,mid+1,r); up(root);}main(){//freopen("in.txt","r",stdin);int m,f,x,d;while(scanf("%d%d",&n,&m)!=EOF){tot=0;build(0,1,n);while(m--){scanf("%d",&f);if(f==1){scanf("%d",&d); int res=request(0,d); printf("%d\n",res);}else {scanf("%d%d",&x,&d);del(0,x,x+d-1);}}}}
NO.3 spoj 375
雖然這題沒過,但還是覺得它的演算法很有意思。實際上就是把一棵樹分成幾條鏈,然後用資料結構去維護。詳見樹鏈剖分吧,我打算下個星期把它幹了!!!
刷了幾個線段樹,感覺對up這個函數理解又加深了,以前覺得線段樹修改之後很難更新,其實把up寫好鳥,就好了賽,有點像廢話,不過這是我自己的理解,很難表達;