BZOJ.4919.[Lydsy1706月賽]大根堆(線段樹合並/啟發式合並)
阿新 • • 發佈:2018-07-13
ron line 位置 大於 啟發式 assert 嚴格 dfs dig
題目鏈接
考慮樹退化為鏈的情況,就是求一個最長(嚴格)上升子序列。
對於樹,不同子樹間是互不影響的。仿照序列上的LIS,對每個點x維護一個狀態集合,即合並其子節點的集合,然後用val[x]替換掉第一個大於它的數(有等於的就不換了)。
最後根節點狀態集合的大小就是答案了。
關於替換數,可以先找到這個數的位置,如果有這個數就不用管了;沒有的話插入進去,然後遞歸回去,找到一個靠右的位置刪掉。
當然其實不用線段樹合並這麽麻煩,直接上multiset啟發式合並就可以了。。
註意是合並了子樹的狀態,so葉節點sz[]>1也是對的!不要直接置為0!
//64956kb 1288ms #include <cstdio> #include <cctype> #include <cassert> #include <algorithm> //#define gc() getchar() #define MAXIN 300000 #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=2e5+5; int n,A[N],cnt,ref[N],root[N],Enum,H[N],nxt[N],to[N]; char IN[MAXIN],*SS=IN,*TT=IN; struct Segment_Tree { #define S N*19 #define lson son[x][0] #define rson son[x][1] int tot,sz[S],son[S][2]; bool flag; #define Update(x) sz[x]=sz[lson]+sz[rson] void Delete(int x,int l,int r) { if(l==r) { flag=0, --sz[x];//not sz[x]=0! return; } if(sz[lson]) Delete(lson,l,l+r>>1); else/*if(sz[rson])*/ Delete(rson,(l+r>>1)+1,r); Update(x); } void Insert(int &x,int l,int r,int p) { if(!x) x=++tot; if(l==r) { if(!sz[x]) flag=1, ++sz[x]; return; } int m=l+r>>1; if(p<=m) { Insert(lson,l,m,p); if(flag&&sz[rson]) Delete(rson,m+1,r);//新建的時候肯定刪不了啊(沒有右子樹) } else Insert(rson,m+1,r,p); Update(x); } int Merge(int x,int y) { if(!x||!y) return x^y; lson=Merge(lson,son[y][0]), rson=Merge(rson,son[y][1]); sz[x]+=sz[y], sz[y]=0; return x; } }T; 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; } inline void AddEdge(int u,int v){ /*if(u)*/ to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum; } int Find(int x) { int l=1, r=cnt, mid; while(l<r) if(ref[mid=l+r>>1]<x) l=mid+1; else r=mid; return l; } void DFS(int x) { for(int i=H[x]; i; i=nxt[i]) DFS(to[i]), root[x]=T.Merge(root[x],root[to[i]]); T.flag=0, T.Insert(root[x],1,cnt,A[x]); } int main() { n=read(); for(int i=1; i<=n; ++i) ref[i]=A[i]=read(), AddEdge(read(),i); std::sort(ref+1,ref+1+n), cnt=1; for(int i=2; i<=n; ++i) if(ref[i]!=ref[i-1]) ref[++cnt]=ref[i]; for(int i=1; i<=n; ++i) A[i]=Find(A[i]); DFS(1), printf("%d\n",T.sz[root[1]]); return 0; }
BZOJ.4919.[Lydsy1706月賽]大根堆(線段樹合並/啟發式合並)