【[SDOI2017]树点涂色】LCT维护DFS序+LCA+线段树

这不是纯种的LCT,,,,是LCT+LCA+DFS序(或者重链剖分)+线段树,最近学的全用进来了,,很有喧宾夺主的意味。。。(老板说这道题的核心就是LCT+线段树,,假的,,应该是LCT+DFS序。。。) luogu传送门:https://www.luogu.org/problemnew/show/P3703

首先他是每一次都涂一种不同的颜色,就不用具体存储具体的颜色。 我们看到第1个操作,这和LCT的ACCESE很有相似之处。于是我们就想到,设定一个SPLAY就是一个颜色集合的话,那么这个操作1就是一个裸的ACCES操作就好了

第2个操作求AB两点间的路径上的权值,转化为节点到根经过了多少个splay,num[x],num[a]+num[b]-num[lca(a,b)]*2+1 第3个操作求子树里面的最大num,可以dfs序+线段树维护。 设定num[x]为从x节点开始,往上走到根经过了多少个splay,在开始的时候所有节点都各自为一个splay,此时的num[x]就是每一个节点的深度dep,在dfs的时候就可以搞出来。 想到这个LCT,没有link,没有cut,只有虚实边的转化,于是乎只有Acces会调整他的num值(切换左右儿子的时候)。考虑到每连上去一条边,原本连到的那个结点(切换点的后继)的子树从 id[x]到id[x]+siz[x]-1都会加上一个1(多了一个虚边多了一个到根节点的splay),之后连到的那个结点的id[x]+siz[x]-1都会减去一个1。

我们考虑线段树维护其区间max,每次ACCES加减就是max的区间修改,而第三问则直接询问子树上的区间Max。

注意我们splay维护的dfs序,在考虑切换重边的时候要考虑到找到深度最小的点(因为这个卡了两个小时的蒟蒻)。

要找LCA,由于这其实是一个静态的树,我们可以LCA转RMQ,,由于本蒟蒻很弱,直接写的倍增。。。

于是就搞定啦!

code:

#include<stdio.h>
#include<bits/stdc++.h>
#define midd ((l+r)>>1)
#define zig(x) zigzag(x,1)
#define zag(x) zigzag(x,2)
using namespace std;
int n,m;
int owo,la[100005],nt[200005],en[200005];
void addedge(int a,int b)
{
    en[++owo]=b; nt[owo]=la[a]; la[a]=owo;
}
int idcnt,id[100005],old[100005],maxr[100005],dep[100005];
int fa[100005],ls[100005],rs[100005];
struct node
{
    int ll,rr,mx,lazy;
}z[8*100005];
void maketree(int p,int l,int r)
{
    z[p].ll=l; z[p].rr=r;
    if(l==r) { z[p].mx=dep[old[l]]; return; } 
    maketree(p<<1,l,midd);
    maketree(p<<1|1,midd+1,r);
    z[p].mx=max(z[p<<1].mx,z[p<<1|1].mx);
}
void ppd(int p)
{
	if(z[p].ll==z[p].rr||(!z[p].lazy)) return;
    z[p<<1].lazy+=z[p].lazy;
    z[p<<1|1].lazy+=z[p].lazy;
    z[p<<1].mx+=z[p].lazy;
    z[p<<1|1].mx+=z[p].lazy;
    z[p].lazy=0;
}
bool isroot(int x) { return ((!fa[x])||(ls[fa[x]]!=x&&rs[fa[x]]!=x)); } 
void zigzag(int x,int knd) 
{ 
    int y=fa[x]; int z=fa[y]; 
    if(!isroot(y)) 
    { 
        if(ls[z]==y) ls[z]=x; 
        else rs[z]=x; 
    } 
    fa[x]=z; fa[y]=x; 
    if(knd==1) 
    { 
        ls[y]=rs[x]; 
        fa[ls[y]]=y; 
        rs[x]=y; 
    } 
    else 
    { 
        rs[y]=ls[x]; 
        fa[rs[y]]=y; 
        ls[x]=y; 
    } 
}
void splay(int x) 
{ 
    int y,z; 
    while(!isroot(x)) 
    { 
        y=fa[x]; z=fa[y]; 
        if(isroot(y)) 
        { 
            if(ls[y]==x) zig(x); 
            else zag(x); 
        } 
        else 
        { 
            if(ls[z]==y) 
            { 
                if(ls[y]==x) { zig(y); zig(x); } 
                else { zag(x); zig(x); }  
            } 
            else 
            { 
                if(rs[y]==x) { zag(y); zag(x); } 
                else { zig(x); zag(x); } 
            }  
        } 
    } 
}
void update(int p,int x,int y,int d)
{
    if(x<=z[p].ll&&z[p].rr<=y) { z[p].mx+=d; z[p].lazy+=d; return; }
    if(z[p].lazy) ppd(p);
    if(z[p<<1].rr>=x&&z[p<<1].ll<=y) update(p<<1,x,y,d);
    if(z[p<<1|1].rr>=x&&z[p<<1|1].ll<=y) update(p<<1|1,x,y,d);
    z[p].mx=max(z[p<<1|1].mx,z[p<<1].mx);
}
int mmm(int x)
{
	while(ls[x]) x=ls[x];
	return x;
}
void acc(int x)
{
    for(int y=0;x;y=x,x=fa[x])
    {
        splay(x);
        if(rs[x])
        {
        	int z=mmm(rs[x]);
            update(1,id[z],maxr[z],1);
        }
        rs[x]=y;
        if(y)
        {
        	int z=mmm(y);
            update(1,id[z],maxr[z],-1);
        }
    }
}


int getmax(int p,int x,int y)
{
    if(x<=z[p].ll&&z[p].rr<=y) return z[p].mx;
    if(z[p].lazy) ppd(p);
    int lmax=-0x3f3f3f3f,rmax=-0x3f3f3f3f;
    if(z[p<<1].rr>=x&&z[p<<1].ll<=y) lmax=getmax(p<<1,x,y);
    if(z[p<<1|1].rr>=x&&z[p<<1|1].ll<=y) rmax=getmax(p<<1|1,x,y);
    return max(lmax,rmax);
}
int pa[100005][30];
int lcaa(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int k=dep[x]-dep[y],i=0;k;i++,k>>=1)
    {
        if(k&1) x=pa[x][i];
    }
    if(x==y) return x;
    for(int k=20;k>=0;k--)
    {
        if(pa[x][k]!=pa[y][k]) { x=pa[x][k]; y=pa[y][k]; }
    }
    return pa[x][0];
}

void dfs(int x,int ba)
{
    pa[x][0]=ba;
    dep[x]=dep[ba]+1;
    for(int k=20,i=1;i<=k;i++) pa[x][i]=pa[pa[x][i-1]][i-1];
    fa[x]=ba;
    id[x]=++idcnt;
	old[idcnt]=x;
	for(int it=la[x];it;it=nt[it])
    {
        if(en[it]!=ba)
        {
            dfs(en[it],x);
        }
    }
    maxr[x]=idcnt;
}
int query(int p,int x)
{
    if(z[p].ll==z[p].rr) return z[p].mx;
        if(z[p].lazy) ppd(p);
    if(x<=z[p<<1].rr) return query(p<<1,x);
    else return query(p<<1|1,x);
}
int main()
{
//	freopen("date.in","r",stdin);
//	freopen("zhengjie.out","w",stdout);
    int a,b;
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a);
    }
    dfs(1,0);
    maketree(1,1,n);
    int kkk,x;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&kkk);
        if(kkk==1)
        {
            scanf("%d",&x);
            acc(x);
        }
        else if(kkk==2)
        {
            scanf("%d%d",&a,&b);
            int aha=lcaa(a,b);
            int aaaa=query(1,id[a])+query(1,id[b])-query(1,id[aha])*2+1;
            printf("%d\n",aaaa);
        }
        else
        {
            scanf("%d",&a);
            printf("%d\n",getmax(1,id[a],maxr[a]));
        }
    }
} 

 

posted @ 2018-04-11 16:12  Newuser233  阅读(7)  评论(0)    收藏  举报