spoj Qtree6/bzoj 3637 Query on a tree VI(树链剖分+线段树/LCT)

题意:

思路:

首先,我们要开两颗线段树,一颗表示,当前节点为白时,和子树所组成的最大联通块大小是多少,另一颗表示,当前节点为黑时,和子树所组成的最大联通块大小是多少。
那么我们查询点u的答案的时候,就向上找到最远的相同颜色的点v,点v所保存的答案就是u的答案(我们v为最远同色祖先)。
更新某个点u的颜色的时候,就是把u的父亲和最远同色祖先的父亲,这一条路径上的都更新(注意,黑白各更新一次,且将对应不同路径),为什么是把u的父亲和最远同色祖先的父亲更新一次,这个根据我们之前对他们的定义就能理解了,这里用树剖+线段树维护即可。
那么还有一个问题,怎么快速找到最远公共祖先,就是树剖爬,然后二分某个链即可(注意你二分的时候左右值分别表示的是什么)
最后,注意根,以及你在爬的时候,每个点表示的颜色

错误及反思:

卡了两天,真的毒啊,各种边界,各种细节,一个人慢慢摸索了好久才AC
这个代码在spoj过了,在bzojT了,把线段树改成树状数组应该就能AC了,可是我实在不想改了(不过代码写的很丑,主要是确实改烦了)

代码:

#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int N =100010;

int tot=0,tid=1,n,q;
int top[N],si[N],fa[N],first[N],son[N],depth[N],id[N],rnk[N];
int cnt[N*4],segtree[2][N*4],lazy[2][N*4];//0 for white 1 for black
// cnt calculate for white   so 0 for black 1 for white

struct E{
    int to,next;
}e[N*2];

void build(int l,int r,int rt){
    if(l==r){
        segtree[1][rt]=si[rnk[l]];
        segtree[0][rt]=1;
        return ;
    }
    int m=(l+r)/2;
    build(lson); build(rson);
}

void addedge(int x,int y){
    e[tot].to=y;
    e[tot].next=first[x];
    first[x]=tot++;
}

void dfs1(int now,int bef,int dep){
    fa[now]=bef;
    depth[now]=dep;
    si[now]=1;
    for(int i=first[now];i!=-1;i=e[i].next)
        if(e[i].to!=bef){
            dfs1(e[i].to,now,dep+1);
            si[now]+=si[e[i].to];
            if(son[now]==-1) son[now]=e[i].to;
            else son[now]=si[e[i].to]>si[son[now]]?e[i].to:son[now];
        }
}

void dfs2(int now,int tp){
    top[now]=tp;
    id[now]=tid++;
    if(son[now]!=-1) dfs2(son[now],tp);
    for(int i=first[now];i!=-1;i=e[i].next)
        if(e[i].to!=fa[now]&&e[i].to!=son[now])
            dfs2(e[i].to,e[i].to);
}

void init(){
    memset(first,-1,sizeof(first));
    memset(son,-1,sizeof(son));
}

void pushdown(int x,int l,int r,int rt){
    if(lazy[x][rt]){
        lazy[x][rt<<1]+=lazy[x][rt];
        lazy[x][rt<<1|1]+=lazy[x][rt];
        segtree[x][rt<<1]+=lazy[x][rt];
        segtree[x][rt<<1|1]+=lazy[x][rt];
        lazy[x][rt]=0;
    }
}

void changecnt(int p,int l,int r,int rt){
    if(l==r){
        cnt[rt]=!cnt[rt];
        return ;
    }
    int m=(l+r)/2;
    if(m>=p) changecnt(p,lson);
    else changecnt(p,rson);
    cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
}

void changeseg(int L,int R,int v,int l,int r,int rt,int x){
    if(L<=l&&R>=r){
        lazy[x][rt]+=v;
        segtree[x][rt]+=v;
        return ;
    }
    pushdown(x,l,r,rt);
    int m=(l+r)/2;
    if(L<=m) changeseg(L,R,v,lson,x);
    if(R>m) changeseg(L,R,v,rson,x);
}

int querycnt(int L,int R,int l,int r,int rt){
    if(L<=l&&R>=r) return cnt[rt];
    int m=(l+r)/2,ans=0;
    if(m>=L) ans+=querycnt(L,R,lson);
    if(m<R) ans+=querycnt(L,R,rson);
    return ans;
}

int queryseg(int p,int l,int r,int rt,int x){
    if(l==r)return segtree[x][rt];
    int m=(l+r)/2;
    pushdown(x,l,r,rt);
    if(m>=p) return queryseg(p,lson,x);
    return queryseg(p,rson,x);
}

int getans(int u){
    int f=top[u],col=querycnt(id[u],id[u],1,n,1);
    while(f!=1){
        int x=querycnt(id[f],id[u],1,n,1);
        if(col&&x!=depth[u]-depth[f]+1) break;
        if(!col&&x) break;
        if(col!=querycnt(id[fa[f]],id[fa[f]],1,n,1)) break;
        u=fa[f];
        f=top[u];
    }

    while(id[u]>id[f]+1){
        int m=(id[u]+id[f])/2;
        int x=querycnt(m,id[u],1,n,1);
        if(col){
            if(x==depth[u]-depth[rnk[m]]+1) u=rnk[m];
            else f=rnk[m];
        }
        else{
            if(x==0) u=rnk[m];
            else f=rnk[m];
        }
    }
    if(querycnt(id[fa[u]],id[fa[u]],1,n,1)==col) u=fa[u];

    return queryseg(id[u],1,n,1,!col);
}

void modify(int u){
    int v=u;
    int col=querycnt(id[u],id[u],1,n,1),num=queryseg(id[u],1,n,1,!col);
    changecnt(id[u],1,n,1);
    if(u==1) return ;

    u=fa[u];
    int f=top[u];

    while(f!=1){
        int x=querycnt(id[f],id[u],1,n,1);
        if(col&&x!=depth[u]-depth[f]+1) break;
        else if(col) changeseg(id[f],id[u],-num,1,n,1,!col);

        if(!col&&x) break;
        else if(!col) changeseg(id[f],id[u],-num,1,n,1,!col);

        u=fa[f];
        f=top[u];
    }

    while(id[u]>id[f]+1){
        int m=(id[u]+id[f])/2;
        int x=querycnt(m,id[u],1,n,1);
        if(col){
            if(x==depth[u]-depth[rnk[m]]+1){
                changeseg(m+1,id[u],-num,1,n,1,!col);
                u=rnk[m];
            }
            else f=rnk[m];
        }
        else{
            if(x==0){
                changeseg(m+1,id[u],-num,1,n,1,!col);
                u=rnk[m];
            }
            else f=rnk[m];
        }
    }
    if(u!=f&&col==querycnt(id[u],id[u],1,n,1)) changeseg(id[u],id[u],-num,1,n,1,!col);
    if(col!=querycnt(id[u],id[u],1,n,1)) f=u;
    changeseg(id[f],id[f],-num,1,n,1,!col);

    u=v;
    col=!col;
    num=queryseg(id[u],1,n,1,!col);
    u=fa[u];
    f=top[u];
    while(f!=1){
        int x=querycnt(id[f],id[u],1,n,1);
        if(col&&x!=depth[u]-depth[f]+1) break;
        else if(col) changeseg(id[f],id[u],num,1,n,1,!col);

        if(!col&&x) break;
        else if(!col) changeseg(id[f],id[u],num,1,n,1,!col);
        u=fa[f];
        f=top[u];
    }

    while(id[u]>id[f]+1){
        int m=(id[u]+id[f])/2;
        int x=querycnt(m,id[u],1,n,1);
        if(col){
            if(x==depth[u]-depth[rnk[m]]+1){
                changeseg(m+1,id[u],num,1,n,1,!col);
                u=rnk[m];
            }
            else f=rnk[m];
        }
        else{
            if(x==0){
                changeseg(m+1,id[u],num,1,n,1,!col);
                u=rnk[m];
            }
            else f=rnk[m];
        }
    }
    if(u!=f&&col==querycnt(id[u],id[u],1,n,1)) changeseg(id[u],id[u],num,1,n,1,!col);
    if(col!=querycnt(id[u],id[u],1,n,1)) f=u;
    changeseg(id[f],id[f],num,1,n,1,!col);
    return ;
}

int main(){
    init();
    scanf("%d",&n);
    for(int i=0,u,v;i<n-1;i++){
        scanf("%d%d",&u,&v);
        addedge(u,v); addedge(v,u);
    }
    dfs1(1,1,1); dfs2(1,1);
    for(int i=1;i<=n;i++) rnk[id[i]]=i;
    build(1,n,1);
    scanf("%d",&q);
    while(q--){
        int k,u;
        scanf("%d%d",&k,&u);
        if(k) modify(u);
        else printf("%d\n",getans(u));
    }
}

猜你喜欢

转载自blog.csdn.net/roll_keyboard/article/details/80553610
今日推荐