Luogu P3703 [SDOI2017]樹點塗色
阿新 • • 發佈:2019-02-23
opera esp rotate acc file clu head dfs序 復雜度分析
復雜度是\(O(n\log^2n)\)的(復雜度分析類似於LCT上的平衡樹操作)
比較有趣的綜合樹上問題,刷LCT題單時做的但是發現後面LCT只是起了輔助作用233
首先我們分析每一個操作,\(1\)的定義就讓我們聯想到了access
,我們回憶一下LCT的性質:
LCT中每一個splay保存的都是原樹上深度連續的一條鏈。
那麽我們發現由於這裏的染色是染上全新的一種顏色,所以每一次access
後的每棵splay維護的都是同種顏色的點鏈,是同時符合性質和題目要求的
不過註意由於這裏是染新的顏色,所以是可以用access
的,如果是染成之前的某種顏色那麽就不能這麽做!
好了想完修改我們來考慮詢問,首先看\(2\)操作,詢問路徑的顏色個數?
由於這是一棵有根樹,結合前面的操作我們容易想到維護每個點到根節點的顏色個數記為\(col_i\)
容易發現這裏的\(col\)具有可減性,那麽維護路徑顏色個數就可以用樹上差分
具體的,路徑\(x,y\)之間的顏色個數就是\(col_x+col_y-2\cdot col_{\operatorname{LCA}(x,y)}+1\)
這個和求樹上兩點間距離類似,不過就是\(\operatorname{LCA}\)的顏色會被減兩次所以要加回去
然後就是\(3\)操作,我們發現當我們維護了\(col\)之後其實就是詢問一個子樹內最大的\(col\)
子樹信息想到什麽,DFS序啊!結合前面的access
時進行的也是子樹修改,我們容易想到維護區間修改區間查最大值的線段樹,這樣結合access
的期望\(\log\)
那麽就代碼實現方面,DFS序都要寫了,那麽順帶寫一下樹剖吧,一般跳的比倍增快一些
然後就是碼農時刻了,建議把代碼分塊一下要不然很容易調死不出
奉上近\(200\)行的CODE
#include<cstdio> #include<cctype> #define RI register int #define CI const int& #define Tp template <typename T> using namespace std; const int N=100005; struct edge { int to,nxt; }e[N<<1]; int n,m,head[N],cnt,opt,x,y,fa,id[N],dep[N],dfn[N],size[N]; class FileInputOutput { private: static const int S=1<<21; #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++) #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch)) char Fin[S],Fout[S],*A,*B; int pt[15],Ftop; public: Tp inline void read(T& x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); } Tp inline void write(T x) { if (!x) return (void)(pc('0'),pc('\n')); RI ptop=0; while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('\n'); } inline void Fend(void) { fwrite(Fout,1,Ftop,stdout); } #undef tc #undef pc }F; class Segment_Tree { private: struct Segment { int mx,tag; }node[N<<2]; #define M(x) node[x].mx #define T(x) node[x].tag inline int max(CI a,CI b) { return a>b?a:b; } inline void add(CI now,CI mv) { M(now)+=mv; T(now)+=mv; } inline void pushup(CI now) { M(now)=max(M(now<<1),M(now<<1|1)); } inline void pushdown(CI now) { if (T(now)) add(now<<1,T(now)),add(now<<1|1,T(now)),T(now)=0; } public: #define TN CI now=1,CI l=1,CI r=n inline void build(TN) { if (l==r) return (void)(M(now)=dep[id[l]]); int mid=l+r>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); pushup(now); } #define O beg,end inline void modify(CI beg,CI end,CI mv,TN) { if (beg<=l&&r<=end) return add(now,mv); int mid=l+r>>1; pushdown(now); if (beg<=mid) modify(O,mv,now<<1,l,mid); if (end>mid) modify(O,mv,now<<1|1,mid+1,r); pushup(now); } inline int query(CI beg,CI end,TN) { if (beg<=l&&r<=end) return M(now); int mid=l+r>>1,ret=0; pushdown(now); if (beg<=mid) ret=max(ret,query(O,now<<1,l,mid)); if (end>mid) ret=max(ret,query(O,now<<1|1,mid+1,r)); return ret; } #undef TN #undef O #undef M #undef T }T; class Link_Cut_Tree { private: struct splay { int ch[2],fa; }node[N]; #define lc(x) node[x].ch[0] #define rc(x) node[x].ch[1] #define fa(x) node[x].fa inline void connect(CI x,CI y,CI d) { node[fa(x)=y].ch[d]=x; } inline int identify(CI now) { return rc(fa(now))==now; } inline bool isroot(CI now) { return lc(fa(now))!=now&&rc(fa(now))!=now; } inline void rotate(CI now) { int x=fa(now),y=fa(x),d=identify(now); if (!isroot(x)) node[y].ch[identify(x)]=now; fa(now)=y; connect(node[now].ch[d^1],x,d); connect(x,now,d^1); } inline void splay(int now) { for (int t;!isroot(now);rotate(now)) t=fa(now),!isroot(t)&&(rotate(identify(now)!=identify(t)?now:t),0); } inline int findroot(int now) { while (lc(now)) now=lc(now); return now; } public: inline void link(CI x,CI y) { fa(x)=y; } inline void access(int x) { for (int y=0,t;x;x=fa(y=x)) { splay(x); if (rc(x)) t=findroot(rc(x)),T.modify(dfn[t],dfn[t]+size[t]-1,1); if (rc(x)=y) t=findroot(rc(x)),T.modify(dfn[t],dfn[t]+size[t]-1,-1); } } #undef lc #undef rc #undef fa }LCT; class Light_Heavy_Division { private: int idx,top[N],father[N],son[N]; inline void swap(int& x,int& y) { int t=x; x=y; y=t; } public: #define to e[i].to inline void DFS1(CI now,CI fa) { size[now]=1; dep[now]=dep[fa]+1; father[now]=fa; for (RI i=head[now];i;i=e[i].nxt) if (to!=fa) { DFS1(to,now); size[now]+=size[to]; LCT.link(to,now); if (size[to]>size[son[now]]) son[now]=to; } } inline void DFS2(CI now,CI tf) { id[dfn[now]=++idx]=now; top[now]=tf; if (son[now]) DFS2(son[now],tf); for (RI i=head[now];i;i=e[i].nxt) if (to!=father[now]&&to!=son[now]) DFS2(to,to); } inline int get_LCA(int x,int y) { while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); x=father[top[x]]; } return dep[x]<dep[y]?x:y; } #undef to }L; inline void add(CI x,CI y) { e[++cnt]=(edge){y,head[x]}; head[x]=cnt; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i; for (F.read(n),F.read(m),i=1;i<n;++i) F.read(x),F.read(y),add(x,y),add(y,x); for (L.DFS1(1,0),L.DFS2(1,1),T.build(),i=1;i<=m;++i) { F.read(opt); F.read(x); switch (opt) { case 1: LCT.access(x); break; case 2: F.read(y); fa=L.get_LCA(x,y); F.write(T.query(dfn[x],dfn[x])+T.query(dfn[y],dfn[y])- (T.query(dfn[fa],dfn[fa])<<1)+1); break; case 3: F.write(T.query(dfn[x],dfn[x]+size[x]-1)); break; } } return F.Fend(),0; }
Luogu P3703 [SDOI2017]樹點塗色