bzoj4817: [Sdoi2017]树点涂色

mac2022-07-05  32

题目链接

bzoj4817: [Sdoi2017]树点涂色

题解

数据结构.....大概很容易看出是道lct 然后弃疗 操作1很想lct里面的access操作 那么对于操作2 设F[i]=i点到lct根路径上的splay数(也就是虚边数)+1 那么对于操作2的(x,y) ans(x,y)=F[x]+F[y]-(F(lca(x,y)))+1; 对于操作3的(x),就是在x的子树中取max,我们可以用dfs序+线段树维护 考虑操作1对操作3的影响 在access的时候,当一个边由虚变实,此时该边所连的深度大的点的颜色种类-1 反之当一边由实变虚,此时该边所连的深度大的点的颜色种类+1 trick:保存当前节点在树中最左儿子的编号用以修改区间(即left[]) ps:中途电脑爆炸,然后重码QAQ,心态爆炸

代码

/* * * 数据结构+LCT+SEG_TREE * */ #include<cstdio> #include<algorithm> const int maxn = 100007; int n,m; struct node{ int v,next; }edge[maxn<<1]; int head[maxn],num; void Add_Edge(int u,int v) { edge[++num].v=v;edge[num].next=head[u];head[u]=num; } int idfn[maxn],ldfn[maxn],rdfn[maxn],f[maxn][20],dep[maxn]; int cnt=0,fa[maxn]; void dfs(int u,int F) { idfn[ldfn[u]=++cnt]=u,f[u][0]=fa[u]=F; for(int i=head[u];i;i=edge[i].next) { int v=edge[i].v; if(v!=F) dep[v]=dep[u]+1,dfs(v,u); } rdfn[u]=cnt; return ; } int LCA(int x,int y) { if(dep[x]<dep[y]) std::swap(x,y); for(int i=dep[x]-dep[y],j=0;i;i>>=1,++j) if(i&1)x=f[x][j]; if(x==y) return x; for(int i=19;~i;--i) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } class Segment_Tree { #define lc x<<1 #define rc x<<1|1 private : struct Node { int max,tag; Node () : tag(0){} }; Node t[maxn<<2]; void update(int x) { t[x].max=std::max(t[lc].max,t[rc].max); } void push_down(int x) { if(!t[x].tag)return; int k=t[x].tag; t[lc].max+=k; t[lc].tag+=k; t[rc].max+=k; t[rc].tag+=k; t[x].tag=0; return ; } public : void build (int x,int l,int r) { if(l==r) { t[x].max=dep[idfn[l]]+1;return; } int mid=l+r>>1; build(lc,l,mid); build(rc,mid+1,r); return update(x); } void modify(int x,int l,int r,int L,int R,int w) { if(L<=l&&R>=r) { t[x].tag+=w;t[x].max+=w; return ; } push_down(x); int mid=l+r>>1; if(mid>=L) modify(lc,l,mid,L,R,w); if(mid<R) modify(rc,mid+1,r,L,R,w); return update(x); } int query(int x,int l,int r,int L,int R) { if(L<=l&&R>=r) return t[x].max; push_down(x); int mid=l+r>>1,ans=0; if(mid>=L) ans=std::max(ans,query(lc,l,mid,L,R)); if(mid<R) ans=std::max(ans,query(rc,mid+1,r,L,R)); return ans; } #undef lc #undef rc }SEG_T; class Link_Cut_tree { #define lc ch[x][0] #define rc ch[x][1] private : int ch[maxn][2],left[maxn]; void update(int x) { left[x]=lc ? left[lc]:x; } bool isroot(int x) { return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; } void rotate(int x) { int y=fa[x],z=fa[y],d=(ch[y][1]==x)^1; if(!isroot(y)) ch[z][ch[z][1]==y]=x;fa[x]=z; ch[y][d^1]=ch[x][d],fa[ch[x][d]]=y; ch[x][d]=y;fa[y]=x; update(y),update(x); } void splay(int x) { while(!isroot(x)) { int y=fa[x],z=fa[y]; if(!isroot(y)) { if(ch[y][1]==x^ch[z][1]==y) rotate(x); else rotate(y); } rotate(x); } } public: void init() { dfs(1,0),SEG_T.build(1,1,n); for(int i=1;i<=n;++i) left[i]=i; for(int j=1;j<20;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; } void access(int x) { for(int t=0;x;x=fa[t=x]) { splay(x); if(rc) SEG_T.modify(1,1,n,ldfn[left[rc]],rdfn[left[rc]],1); rc=t; if(rc) SEG_T.modify(1,1,n,ldfn[left[rc]],rdfn[left[rc]],-1); } return ; } int query(int x) { int ans=0; for(;x;x=fa[x],ans++)splay(x); return ans; } int query(int u,int v) { return query(u)+query(v)-2*query(LCA(u,v))+1; } #undef lc #undef rc }LCT; int main() { // freopen("001.out","w",stdout); scanf("%d%d",&n,&m) ; for(int a,b,i=1;i<n;++i) { scanf("%d%d",&a,&b); Add_Edge(a,b); Add_Edge(b,a); } LCT.init(); for(int opt,x,y,i=1;i<=m;++i) { scanf("%d",&opt); if(opt==1) scanf("%d",&x),LCT.access(x); if(opt==2) scanf("%d%d",&x,&y),printf("%d\n",LCT.query(x,y)); else if(opt==3) scanf("%d",&x),printf("%d\n",SEG_T.query(1,1,n,ldfn[x],rdfn[x])); } return 0; }

转载于:https://www.cnblogs.com/sssy/p/8641568.html

最新回复(0)