bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】

非常妙的一道题。
首先对于操作一“把点x到根节点的路径上所有的点染上一种没有用过的新颜色”,长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT中的重边的话,那么询问二就相当于问路径上的虚边有多少。
然后第二、三个操作是可以用树剖在线段树上维护的。
设每个点的权值\( val \)为这个点到根的路径上颜色个数,也就是虚边个数。那么考虑access操作的影响,对于他断开的重边,所在子树加一,对于他连上的重边,所在子树减一。直接在access过程中处理即可。
对于操作一,直接access;
对于操作二,\( ans=val[x]+val[y]-2*val[lca(x,y)]+1 \);
对于操作三,用线段树维护区间最大值,直接查询即可。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,m,h[N],cnt,si[N],fa[N],de[N],hs[N],fr[N],id[N],tmp,rl[N];
struct qwe
{
	int ne,to;
}e[N<<1];
struct xianduanshu
{
	int l,r,mx,lz;
}q[N<<2];
struct pinghengshu
{
	int f,c[2];
}t[N];
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(f==-1)
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
void add(int u,int v)
{
	cnt++;
	e[cnt].ne=h[u];
	e[cnt].to=v;
	h[u]=cnt;
}
void dfs1(int u,int fat)
{
    fa[u]=fat;
    de[u]=de[fat]+1;
    si[u]=1;
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fat)
        {
            dfs1(e[i].to,u);
            si[u]+=si[e[i].to];
            if(si[e[i].to]>si[hs[u]])
                hs[u]=e[i].to;
        }
}
void dfs2(int u,int top)
{
    fr[u]=top;
    id[u]=++tmp;
    rl[tmp]=u;
    if(!hs[u])
        return;
    dfs2(hs[u],top);
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fa[u]&&e[i].to!=hs[u])
            dfs2(e[i].to,e[i].to);
}
int lca(int u,int v)
{
    for(;fr[u]!=fr[v];de[fr[u]]>de[fr[v]]?u=fa[fr[u]]:v=fa[fr[v]]);//cout<<u<<" "<<v<<" "<<" ";if(de[u]>de[v])cout<<v;else cout<<u;cout<<endl;
    return de[u]>de[v]?v:u;
}
void build(int ro,int l,int r)
{
	q[ro].l=l,q[ro].r=r;
	if(l==r)
	{
		q[ro].mx=de[rl[l]];
		// cout<<rl[l]<<" "<<q[ro].mx<<endl;
		return;
	}
	int mid=(l+r)>>1;
	build(ro<<1,l,mid);
	build(ro<<1|1,mid+1,r);
	q[ro].mx=max(q[ro<<1].mx,q[ro<<1|1].mx);
}
void pd(int ro)
{
	q[ro<<1].mx+=q[ro].lz;
	q[ro<<1].lz+=q[ro].lz;
	q[ro<<1|1].mx+=q[ro].lz;
	q[ro<<1|1].lz+=q[ro].lz;
	q[ro].lz=0;
}
void update(int ro,int l,int r,int v)
{//cout<<l<<" "<<r<<" "<<v<<endl;
	if(q[ro].l==l&&q[ro].r==r)
	{
		q[ro].mx+=v;
		q[ro].lz+=v;
		return;
	}
	if(q[ro].lz)
		pd(ro);
	int mid=(q[ro].l+q[ro].r)>>1;
	if(r<=mid)
		update(ro<<1,l,r,v);
	else if(l>mid)
		update(ro<<1|1,l,r,v);
	else
	{
		update(ro<<1,l,mid,v);
		update(ro<<1|1,mid+1,r,v);
	}
	q[ro].mx=max(q[ro<<1].mx,q[ro<<1|1].mx);
}
int ques(int ro,int l,int r)
{
	if(q[ro].l==l&&q[ro].r==r)
		return q[ro].mx;
	if(q[ro].lz)
		pd(ro);
	int mid=(q[ro].l+q[ro].r)>>1;
	if(r<=mid)
		return ques(ro<<1,l,r);
	else if(l>mid)
		return ques(ro<<1|1,l,r);
	else
		return max(ques(ro<<1,l,mid),ques(ro<<1|1,mid+1,r));
}
bool srt(int x)
{
	return t[t[x].f].c[0]!=x&&t[t[x].f].c[1]!=x;
}
void zhuan(int x)
{
	int l,r,y=t[x].f,z=t[y].f;
    if(t[y].c[0]==x)
		l=0;
	else
		l=1;
	r=l^1;
    if(!srt(y))
    {
        if(t[z].c[0]==y)
			t[z].c[0]=x;
		else
			t[z].c[1]=x;
    }
    t[x].f=z;t[y].f=x;
    t[t[x].c[r]].f=y;
    t[y].c[l]=t[x].c[r];
    t[x].c[r]=y;
}
void splay(int x)
{
	while(!srt(x))
	{
		int y=t[x].f,z=t[y].f;
		if(!srt(y))
		{
			if((t[y].c[0]==x)^(t[z].c[0]==y))
				zhuan(x);
			else
				zhuan(y);
		}
		zhuan(x);
	}
}
void acc(int x)
{
	for(int i=0;x;i=x,x=t[x].f)
	{
		splay(x);
		if(t[x].c[1])
		{
			int y=t[x].c[1];
			while(t[y].c[0])
				y=t[y].c[0];
			update(1,id[y],id[y]+si[y]-1,1);
		}
		t[x].c[1]=i;
		if(t[x].c[1])
		{
			int y=t[x].c[1];
			while(t[y].c[0])
				y=t[y].c[0];
			update(1,id[y],id[y]+si[y]-1,-1);
		}
	}
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read();
		add(x,y);add(y,x);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	for(int i=2;i<=n;i++)
		t[i].f=fa[i];
	while(m--)
	{
		int o=read();
		if(o==1)
		{
			int x=read();
			acc(x);
		}
		else if(o==2)
		{
			int x=read(),y=read(),lc=lca(x,y);
			printf("%d\n",ques(1,id[x],id[x])+ques(1,id[y],id[y])-2*ques(1,id[lc],id[lc])+1);
			// printf("%d %d %d %d\n",ques(1,id[x],id[x]),ques(1,id[y],id[y]),ques(1,id[lc],id[lc]),ques(1,id[fa[lc]],id[fa[lc]]));
		}
		else
		{
			int x=read();
			printf("%d\n",ques(1,id[x],id[x]+si[x]-1));
		}
	}
	return 0;
}
posted @ 2018-01-08 20:25  lokiii  阅读(174)  评论(0编辑  收藏  举报