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));
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章