【SPOJ QTREE7】Query on a tree VII(LCT维护树上同色连通块)
- 给定一棵\(n\)个点的树,每个点有一个点权和黑白中的一种颜色。
- 要求支持三种操作:询问一个点所在同色连通块最大点权;翻转一个点的颜色;修改一个点的点权。
- \(n,q\le10^5\)
树上同色连通块
和【SPOJ QTREE6】Query on a tree VI几乎一样。
唯一的区别在于这道题维护的信息是最大值,无法直接加减。
针对这个问题,我们对\(LCT\)上每个点开一个\(multiset\)维护它自身及所有虚儿子最大值。
具体实现起来也差不多。
代码:\(O(nlog^2n)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,a[N+5],c[N+5],ee,lnk[N+5];struct edge {int to,nxt;}e[2*N+5];
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
#define D isdigit(oc=tc())
int ff,OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
Tp I void read(Ty& x) {x=0,ff=1;W(!D) ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),D);x*=ff;}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void writeln(Ty x) {x<0&&(pc('-'),x=-x);W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('\n');}
}using namespace FastIO;
class LinkCutTree
{
private:
#define T(x,v) O[x].G.insert(v)
#define E(x,v) O[x].G.erase(O[x].G.find(v))
#define PU(x) (O[x].Mx=max(*--O[x].G.end(),max(O[O[x].S[0]].Mx,O[O[x].S[1]].Mx)))//上传信息
#define IR(x) (O[O[x].F].S[0]^x&&O[O[x].F].S[1]^x)
#define Wh(x) (O[O[x].F].S[1]==x)
#define Co(x,y,d) (O[O[x].F=y].S[d]=x)
struct node {int Mx,F,S[2];multiset<int> G;}O[N+5];
I void Ro(RI x) {RI f=O[x].F,p=O[f].F,d=Wh(x);
!IR(f)&&(O[p].S[Wh(f)]=x),O[x].F=p,Co(O[x].S[d^1],f,d),Co(f,x,d^1),PU(f);}
I void S(RI x) {RI f;W(!IR(x)) f=O[x].F,!IR(f)&&(Ro(Wh(x)^Wh(f)?x:f),0),Ro(x);PU(x);}
I void Ac(RI x) {for(RI y=0;x;x=O[y=x].F) S(x),y&&(E(x,O[y].Mx),0),T(x,O[O[x].S[1]].Mx),O[x].S[1]=y,PU(x);}
public:
I void Init() {for(RI i=1;i<=n+1;++i) T(i,O[i].Mx=i<=n?a[i]:-1e9);O[0].Mx=-1e9;}//初始化
I void Link(CI x,CI y) {Ac(x),S(x),S(y),O[y].F=x,T(x,O[y].Mx),PU(x);}//连边
I void Cut(CI x,CI y) {Ac(y),S(x),O[x].S[1]=O[y].F=0,PU(x);}//断边
I void U(CI x,CI v) {Ac(x),S(x),E(x,a[x]),T(x,v);}//单点修改
I int Q(RI x) {Ac(x),S(x);W(O[x].S[0]) x=O[x].S[0];return S(x),O[O[x].S[1]].Mx;}//Access(x)并Splay根,询问根节点右儿子信息
}LCT[2];
int fa[N+5];I void dfs(CI x)
{
for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^fa[x]&&(fa[e[i].to]=x,dfs(e[i].to),0);LCT[c[x]].Link(fa[x],x);//预处理建树
}
int main()
{
RI i,x,y,v;for(read(n),i=1;i^n;++i) read(x,y),add(x,y),add(y,x);
for(i=1;i<=n;++i) read(c[i]);for(i=1;i<=n;++i) read(a[i]);LCT[0].Init(),LCT[1].Init(),fa[1]=n+1,dfs(1);
RI Qt;read(Qt);W(Qt--) read(x,y),!x?writeln(LCT[c[y]].Q(y))//询问
:(x==1?(LCT[c[y]].Cut(fa[y],y),LCT[c[y]^=1].Link(fa[y],y)):(void)(read(v),LCT[0].U(y,v),LCT[1].U(y,v),a[y]=v));//翻转;修改
return clear(),0;
}
待到再迷茫时回头望,所有脚印会发出光芒