ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷P3703/LOJ2001/Vijos2014/BZOJ4817[SDOI2017]树点涂色(LCT+树链剖分)

2019-08-14 17:00:07  阅读:186  来源: 互联网

标签:LCT BZOJ4817 int void fa ch maxn 涂色 inline


因为开始每个点颜色不同,染上去的颜色都是新的,由此得出:颜色种数=颜色段数。

然后考虑操作1。它的流程是:从结点x出发,每次跳到同色的链顶端,沿途染色,然后修改链顶的父亲的指向,继续执行,最后得到一条1到x的同色链。

想到了什么?access?没错,用LCT来维护同色点集的话,每次改颜色就是裸的access。

考虑到操作3要求子树内权值最大值,我们考虑维护这个权值$w_u$,那么不难发现操作2的答案因为$w_u+w_v-2w_{lca_{u,v}}+1$(差分,$lca_{u,v}$的颜色被减了两次,加回来)

而对于操作1,每次断边会使这个子树内的$w_u+1$,连边会使子树内的$w_u-1$,可以用dfs序/树链剖分+线段树维护这一过程。

#include<cstdio>
const int N=100050;
char rB[1<<21],*rS,*rT,wB[(1<<21)+50];
int wp=-1;
inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;}
inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
short buf[15];
inline void wt(int x){
    if(wp>(1<<21))flush();
    short l=-1;
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    wB[++wp]=x|48;
    while(l>=0)wB[++wp]=buf[l--]|48;
    wB[++wp]='\n';
}
int G[N],to[N<<1],nxt[N<<1],cnt=0,f[N],ch[N][2],tf[N],dep[N],top[N],son[N],sz[N],id[N],dfsc=0,w[N],maxn[N<<2],addv[N<<2],n;
inline int Max(int a,int b){return a>b?a:b;}
inline void Swap(int &a,int &b){int t=a;a=b;b=t;}
inline void adde(int u,int v){
    to[++cnt]=v;nxt[cnt]=G[u];G[u]=cnt;
    to[++cnt]=u;nxt[cnt]=G[v];G[v]=cnt;
}
//树剖
void dfs1(int u,int fa){
    int i,v,mxn=0;
    dep[u]=dep[f[u]=tf[u]=fa]+1;sz[u]=1;
    for(i=G[u];i;i=nxt[i])if((v=to[i])!=fa){
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>mxn){
            son[u]=v;
            mxn=sz[v];
        }
    }
}
void dfs2(int u,int topf){
    int i,v;
    top[u]=topf;w[id[u]=++dfsc]=dep[u];
    if(son[u]){
        dfs2(son[u],topf);
        for(i=G[u];i;i=nxt[i])if((v=to[i])!=tf[u]&&v!=son[u])dfs2(v,v);
    }
}
inline int lca(int u,int v){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]])Swap(u,v);
        u=tf[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
//线段树
void build(int o,int L,int R){
    if(L==R)maxn[o]=w[L];
    else{
        int lc=o<<1,rc=lc|1,M=L+R>>1;
        build(lc,L,M);build(rc,M+1,R);
        maxn[o]=Max(maxn[lc],maxn[rc]);
    }
}
void add(int o,int L,int R,int x,int y,short k){
    if(x<=L&&y>=R){addv[o]+=k;maxn[o]+=k;}
    else{
        int lc=o<<1,rc=lc|1,M=L+R>>1;
        if(x<=M)add(lc,L,M,x,y,k);
        if(y>M)add(rc,M+1,R,x,y,k);
        maxn[o]=Max(maxn[lc],maxn[rc])+addv[o];
    }
}
int ask(int o,int L,int R,int x,int y){
    if(x<=L&&y>=R)return maxn[o];
    int lc=o<<1,rc=lc|1,M=L+R>>1,ans=0;
    if(x<=M)ans=ask(lc,L,M,x,y);
    if(y>M)ans=Max(ans,ask(rc,M+1,R,x,y));
    return ans+addv[o];
}
//LCT
inline bool nrt(int o){return ch[f[o]][0]==o||ch[f[o]][1]==o;}
inline bool dir(int o){return ch[f[o]][1]==o;}
inline void rot(int o){
    int fa=f[o];
    bool d=dir(o);
    f[o]=f[fa];
    if(nrt(fa))ch[f[fa]][dir(fa)]=o;
    if(ch[fa][d]=ch[o][d^1])f[ch[fa][d]]=fa;
    f[ch[o][d^1]=fa]=o;
}
inline void splay(int o){
    for(;nrt(o);rot(o))if(nrt(f[o]))rot((dir(o)^(dir(f[o])))?o:f[o]);
}
inline int getfa(int o){  //每次都要找到子树的根再修改
    while(ch[o][0])o=ch[o][0];
    return o;
}
inline void access(int x){
    for(int y=0,t;x;x=f[y=x]){
        splay(x);
        if(ch[x][1]){
            t=getfa(ch[x][1]);
            add(1,1,n,id[t],id[t]+sz[t]-1,1);
        }
        if(ch[x][1]=y){
            t=getfa(y);
            add(1,1,n,id[t],id[t]+sz[t]-1,-1);
        }
    }
}
int main(){
    int q,i,u,v,opt,l;
    n=rd();q=rd();
    for(i=1;i<n;++i){
        u=rd();v=rd();
        adde(u,v);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    while(q--){
        opt=rd();u=rd();
        if(opt==1)access(u);
        else if(opt==2){
            l=lca(u,v=rd());
            wt(ask(1,1,n,id[u],id[u])+ask(1,1,n,id[v],id[v])-(ask(1,1,n,id[l],id[l])<<1)+1);
        }else if(opt==3)wt(ask(1,1,n,id[u],id[u]+sz[u]-1));
    }
    flush();
    return 0;
}
View Code

 

标签:LCT,BZOJ4817,int,void,fa,ch,maxn,涂色,inline
来源: https://www.cnblogs.com/sunshine-chen/p/11353141.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有