1. 程式人生 > >Codeforces.264E.Roadside Trees(線段樹 DP LIS)

Codeforces.264E.Roadside Trees(線段樹 DP LIS)

log 0kb set solution efi () gis urn 更新

題目鏈接

\(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值。

但是右邊10棵樹不一定是最高的,雖然它們可以從前面所有樹轉移,但還要滿足高度小於它們。
這可以二維線段樹。但是我們只需要用另一棵線段樹對每個高度維護同樣的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)