[LCT] BZOJ4817.[Sdoi2017]树点涂色

来源:互联网 发布:windows api 关闭窗口 编辑:程序博客网 时间:2024/06/05 08:08

如果将相邻的两个颜色相同的点之间连实边,不同的连虚边,那么答案就是子树中虚边的数量

每次染色就是虚实边之间的转换

就跟LCT一样,那么LCT access的时候处理一下就可以了。

#include <cstdio>#include <iostream>#include <algorithm>using namespace std;const int N=100010;struct NODE{    NODE *ch[2],*f;    int rev,g,mn;}a[N];int n,m,cnt,G[N];struct edge{    int t,nx;}E[N<<1];inline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void rea(int &x){    char c=nc(); x=0;    for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());}inline void Insert(int x,int y){    E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;    E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;}int it,L[N],R[N],Q[N],dpt[N],fa[N][20];void dfs(int x,int f){    fa[x][0]=f; L[x]=++it; Q[it]=x;    dpt[x]=dpt[f]+1;    for(int i=1;i<=17;i++) fa[x][i]=fa[fa[x][i-1]][i-1];    for(int i=G[x];i;i=E[i].nx)        if(E[i].t!=f) dfs(E[i].t,x),a[E[i].t].f=a+x;    R[x]=it;}int mx[N<<2],tag[N<<2],sum[N<<2];inline void add(int g,int x){    sum[g]+=x; tag[g]+=x; mx[g]+=x;}inline void Up(int g){    mx[g]=max(mx[g<<1],mx[g<<1|1]);    sum[g]=sum[g<<1]+sum[g<<1|1];}inline void Push(int g){    if(tag[g])        add(g<<1,tag[g]),add(g<<1|1,tag[g]);    tag[g]=0;}void Build(int g,int l,int r){    if(l==r) return sum[g]=mx[g]=dpt[Q[l]],void();    int mid=l+r>>1;    Build(g<<1,l,mid); Build(g<<1|1,mid+1,r);    Up(g);}void Add(int g,int L,int R,int l,int r,int x){    if(L==l && R==r) return add(g,x);    int mid=L+R>>1; Push(g);    if(r<=mid) Add(g<<1,L,mid,l,r,x);    else if(l>mid) Add(g<<1|1,mid+1,R,l,r,x);    else Add(g<<1,L,mid,l,mid,x),Add(g<<1|1,mid+1,R,mid+1,r,x);    Up(g);}int Query(int g,int L,int R,int l,int r){    if(l==L && r==R) return mx[g];    int mid=L+R>>1; Push(g);    if(r<=mid) return Query(g<<1,L,mid,l,r);    else if(l>mid) return Query(g<<1|1,mid+1,R,l,r);    else return max(Query(g<<1,L,mid,l,mid),Query(g<<1|1,mid+1,R,mid+1,r));}inline int isl(NODE *x){    return !x->f || (x->f->ch[0]!=x && x->f->ch[1]!=x);}inline int isr(NODE *x){    return x->f && x->f->ch[1]==x;}inline void Up(NODE *x){    x->mn=x->g;    if(x->ch[0] && dpt[x->ch[0]->mn]<dpt[x->mn])        x->mn=x->ch[0]->mn;    if(x->ch[1] && dpt[x->ch[1]->mn]<dpt[x->mn])        x->mn=x->ch[1]->mn;}inline void Push(NODE *x){    if(!x->rev) return ;    swap(x->ch[0],x->ch[1]);    if(x->ch[0]) x->ch[0]->rev^=1;    if(x->ch[1]) x->ch[1]->rev^=1;    x->rev^=1;}inline void rot(NODE *x){    NODE *y=x->f,*z=y->f; int wh=isr(x);    if(!isl(y)) z->ch[isr(y)]=x; x->f=z;    if(y->ch[wh]=x->ch[wh^1]) y->ch[wh]->f=y;    (x->ch[wh^1]=y)->f=x; Up(y); Up(x);}void PUSHTOP(NODE *x){    if(!isl(x)) PUSHTOP(x->f);    Push(x);}inline void splay(NODE *x){    PUSHTOP(x);    for(;!isl(x);rot(x))        if(!isl(x->f)) rot(isr(x->f)^isr(x)?x:x->f);}inline void access(NODE *x){    for(NODE *t=0;x;x=x->f){        splay(x);        if(t) Add(1,1,n,L[t->mn],R[t->mn],-1);        if(x->ch[1]) Add(1,1,n,L[x->ch[1]->mn],R[x->ch[1]->mn],1);        x->ch[1]=t; t=x; Up(x);    }}inline int lca(int x,int y){    if(dpt[x]<dpt[y]) swap(x,y);    for(int i=17;~i;i--)        if(dpt[fa[x][i]]>=dpt[y]) x=fa[x][i];    if(x==y) return x;    for(int i=17;~i;i--)        if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];    return fa[x][0];}int main(){    rea(n); rea(m);    for(int i=1;i<=n;i++) a[i].g=a[i].mn=i;    for(int i=1,x,y;i<n;i++)        rea(x),rea(y),Insert(x,y);    dfs(1,0); Build(1,1,n);    while(m--){        int opt,x,y;        rea(opt);        if(opt==1){            rea(x); access(a+x);        }        else if(opt==2){            rea(x); rea(y);            int LCA=lca(x,y);            printf("%d\n",Query(1,1,n,L[x],L[x])+Query(1,1,n,L[y],L[y])-2*Query(1,1,n,L[LCA],L[LCA])+1);        }        else{            rea(x);            printf("%d\n",Query(1,1,n,L[x],R[x]));        }    }    return 0;}
原创粉丝点击