• 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
    ",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
    ",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
    ",ques(1,id[x],id[x]+si[x]-1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    贪心算法
    分治法
    递归法
    查找二 树与图的搜索
    (转载)查找三 哈希表的查找
    (转载)查找一 线性表的查找
    4.写出完整版的strcpy函数
    3.strcpy使用注意(3)
    2.strcpy使用注意(2)
    1.strcpy使用注意
  • 原文地址:https://www.cnblogs.com/lokiii/p/8244745.html
Copyright © 2020-2023  润新知