1. 程式人生 > >bzoj4817: [Sdoi2017]樹點塗色

bzoj4817: [Sdoi2017]樹點塗色

algorithm 根路徑 ini scanf tree AC lct dfs rdf

題目鏈接

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; }

bzoj4817: [Sdoi2017]樹點塗色