Codeforces.264E.Roadside Trees(線段樹 DP LIS)
阿新 • • 發佈:2018-10-05
log 0kb set solution efi () gis urn 更新
但是右邊10棵樹不一定是最高的,雖然它們可以從前面所有樹轉移,但還要滿足高度小於它們。
這可以二維線段樹。但是我們只需要用另一棵線段樹對每個高度維護同樣的DP值(不同位置高度不同),就可以從左到右,直接用線段樹查詢並更新了。
這樣在一棵線段樹上更新完DP值後在另一棵上改一下即可。
題目鏈接
\(Description\)
\(Solution\)
還是看代碼好理解吧。
為了方便,我們將x坐標左右反轉,再將所有高度取反,這樣依然是維護從左到右的LIS,但是每次是在右邊刪除元素。
這樣對於在p剛種的樹,最多只有9棵樹比它高,即它只會轉移到這9棵樹,除這9棵樹外,它可以從1~p-1的任何樹轉移(其它9棵樹除比它高的外 同樣可以從它前面任何樹轉移)。
我們把這9棵樹的DP值暴力刪掉,然後從低到高 從1~pos[h]-1轉移並更新。按高度更新就只需要考慮位置合不合法了。
我們對位置建線段樹維護每個位置的DP值,就只有單點修改、區間max。
對於砍掉右數第k棵樹,設位置為p,因為只有右邊最多9棵樹從它轉移,同樣將它們的DP值暴力刪掉,然後刪掉位置p的DP值。
這可以二維線段樹。但是我們只需要用另一棵線段樹對每個高度維護同樣的DP值(不同位置高度不同),就可以從左到右,直接用線段樹查詢並更新了。
這樣在一棵線段樹上更新完DP值後在另一棵上改一下即可。
復雜度\(O(10n\log n)\)。
總結:是最高的10棵就在維護位置DP值的線段樹上轉移,是最靠右的10棵就在維護高度DP值的線段樹上轉移。最後更新一下另一棵的DP值(都維護一樣的)。
//840ms 12800KB #include <set> #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar() #define MAXIN 50000 //#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) typedef long long LL; const int N=2e5+15; int pos[N],h[N]; std::set<int> st; char IN[MAXIN],*SS=IN,*TT=IN; struct Segment_Tree { #define ls rt<<1 #define rs rt<<1|1 #define lson l,m,ls #define rson m+1,r,rs #define S N<<2 int f[N],mx[S]; #undef S #define Update(rt) mx[rt]=std::max(mx[ls],mx[rs]) void Modify(int l,int r,int rt,int p,int v) { if(l==r) {mx[rt]=v; return;} int m=l+r>>1; if(p<=m) Modify(lson,p,v); else Modify(rson,p,v); Update(rt); } int Query(int l,int r,int rt,int R) { if(r<=R) return mx[rt]; int m=l+r>>1; if(m<R) return std::max(Query(lson,R),Query(rson,R)); return Query(lson,R); } void Insert(int p,int n)//對於新插入的p查詢DP值並更新 { Modify(0,n,1,p,f[p]=Query(0,n,1,p-1)+1); } }Tp,Th; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } int main() { #define Sp 0,n,1 #define Sh 0,m+10,1 int n=read(),m=read();//pos[i]:高i的樹的位置 h[i]:i位置的樹的高度 for(int t=1; t<=m; ++t) if(read()==1)//plant { int p=n-read()+1,ht=t+10-read(); pos[ht]=p, h[p]=ht, st.insert(p); for(int i=ht+1; i<=ht+9; ++i) if(pos[i]) Tp.Modify(Sp,pos[i],0); for(int i=ht; i<=ht+9; ++i) if(pos[i]) { Tp.Insert(pos[i],n); Th.f[i]=Tp.f[pos[i]]; Th.Modify(Sh,i,Th.f[i]); } printf("%d\n",Tp.mx[1]); } else { int k=read(); std::set<int>::iterator it=st.end(); while(k--) --it, Th.Modify(Sh,h[*it],0); Tp.Modify(Sp,*it,0), pos[h[*it]]=0; for(st.erase(it++); it!=st.end(); ++it) { Th.Insert(h[*it],m+10); Tp.f[*it]=Th.f[h[*it]]; Tp.Modify(Sp,*it,Tp.f[*it]); } printf("%d\n",Tp.mx[1]); } return 0; }
Codeforces.264E.Roadside Trees(線段樹 DP LIS)