BZOJ4817[Sdoi2017]树点涂色
传送门
sdoi是真的舒服QAQ
比较神奇的数据结构上树题233
我们观察这个题的性质 发现将一条到1的路径染色很像LCT的access操作 我们不妨将相同颜色的点放在一个splay里面 然后access的时候 一条重边变成轻边的时候其实是 子树内ans +1 可以理解成原来它和它上面的节点颜色原本是相同的 然后断开边表示颜色不同了 轻边变成重边 子树内ans -1 原因同理 于是我们首先需要LCT来维持树的结构
子树内加减->我会dfs序上线段树! 于是我们可以用线段树维护子树内答案 询问3就变成了区间rmq
我们剩下了询问2 询问2怎么做呢? 路径问题! 树上差分!
我们发现这个“权值”也是满足树上差分的性质的 我们可以对其维护它到1号点的ans记为f[i]
于是第二问的答案就是f[x]+f[y]-2*f[lca]+1 (比较神奇 无论lca的颜色是否存在在路径上都是满足这个差分的)
所以我们最后只需要LCT维护树的形态 然后dfs序上线段树维护f 单点查询&区间查询大小值即可QwQ
附代码。(我的代码真的好看233)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 20021225
#define mxn 100010
#define lson x<<1
#define rson x<<1|1
#define fa(x) t[x].fa
#define ls(x) t[x].son[0]
#define rs(x) t[x].son[1]
#define not_root(x) (ls(fa(x))==x||rs(fa(x))==x)
#define ll long long
#define lg 18
using namespace std;
struct node{int son[2],fa;bool rev;}t[mxn];
struct edge{int to,lt;}e[mxn<<1];
int in[mxn],cnt,dep[mxn],dfn[mxn],tot;
int ff[mxn],n,sz[mxn],fa[mxn][lg+1],d[mxn];
struct Segtree
{
int mx[mxn<<2],tag[mxn<<2];
void pushup(int x){mx[x]=max(mx[lson],mx[rson]);}
void pushdown(int x)
{
if(tag[x])
{
mx[lson]+=tag[x];
tag[lson]+=tag[x];
mx[rson]+=tag[x];
tag[rson]+=tag[x];
tag[x]=0;
}
}
void build(int x,int l,int r)
{
if(l==r){mx[x]=ff[d[l]];return;}
int mid=(l+r)>>1;
build(lson,l,mid);build(rson,mid+1,r);
pushup(x);
}
void modify(int x,int l,int r,int LL,int RR,int v)
{
if(l>=LL&&r<=RR){mx[x]+=v;tag[x]+=v;return;}
int mid=(l+r)>>1;pushdown(x);
if(LL<=mid) modify(lson,l,mid,LL,RR,v);
if(RR>mid) modify(rson,mid+1,r,LL,RR,v);
pushup(x);
}
int query(int x,int l,int r,int LL,int RR)
{
if(l>=LL&&r<=RR) return mx[x];
int mid=(l+r)>>1,ans=0;pushdown(x);
if(LL<=mid) ans=max(ans,query(lson,l,mid,LL,RR));
if(RR>mid) ans=max(ans,query(rson,mid+1,r,LL,RR));
return ans;
}
int getans(int x)
{
return query(1,1,n,dfn[x],dfn[x]);
}
}T;
void add(int x,int y)
{
e[++cnt].to=y;e[cnt].lt=in[x];in[x]=cnt;
e[++cnt].to=x;e[cnt].lt=in[y];in[y]=cnt;
}
void rotate(int x)
{
if(!x||!not_root(x)) return;
int f=fa(x),gf=fa(f);
int k=rs(f)==x,p=k^1;
if(not_root(f)) t[gf].son[t[gf].son[1]==f]=x;
t[x].fa=gf;t[f].fa=x;
t[f].son[k]=t[x].son[p];
if(t[x].son[p]) t[t[x].son[p]].fa=f;
t[x].son[p]=f;
}
void splay(int x)
{
while(not_root(x))
{
int f=fa(x),gf=fa(f);
if(not_root(gf))
(rs(f)==x)^(rs(gf)==f)?rotate(x):rotate(f);
rotate(x);
}
}
int findroot(int x)
{
while(ls(x)) x=ls(x);
return x;
}
void access(int x)
{
int y=0,w;
do
{
splay(x);
if(rs(x)) w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,1);
t[x].son[1]=y;
if(rs(x)) w=findroot(rs(x)),T.modify(1,1,n,dfn[w],dfn[w]+sz[w]-1,-1);
y=x;x=t[x].fa;
}while(x);
}
void dfs(int x)
{
ff[x]=dep[x];dfn[x]=++tot;d[tot]=x;sz[x]=1;t[x].fa=fa[x][0];
for(int i=1;i<=lg;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=in[x];i;i=e[i].lt)
{
int y=e[i].to;
if(dep[y]) continue;
dep[y]=dep[x]+1;fa[y][0]=x;
dfs(y);sz[x]+=sz[y];
}
}
int jump(int x,int len)
{
for(int i=0;i<=lg;i++)
if(len&(1<<i))
x=fa[x][i];
return x;
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
x=jump(x,dep[x]-dep[y]);
if(x==y) return x;
for(int i=lg;~i;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int query(int x,int y)
{
return T.getans(x)+T.getans(y)-2*T.getans(lca(x,y))+1;
}
void modify(int x){access(x);}
int qmax(int x)
{
return T.query(1,1,n,dfn[x],dfn[x]+sz[x]-1);
}
int main()
{
int m,x,y,opt;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
}
dep[1]=1;dfs(1);T.build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d",&x);
modify(x);
}
if(opt==2)
{
scanf("%d%d",&x,&y);
printf("%d\n",query(x,y));
}
if(opt==3)
{
scanf("%d",&x);
printf("%d\n",qmax(x));
}
}
return 0;
}