点双学习

学了一下点双和圆方树

感觉圆方树好妙啊

大概就是说还是类似tarjan的做法

考虑dfn[u]>=low[v],那么意味着u和v一个点双,且u是割点

所以u上面的点不能再和v一个点双了

因为如果他们和v在同一个图中

而u是割点,如果我删掉u那么这张图一定不连通

所以v所在的点双到此结束

因此开始出栈

出栈的时候建立一个方点,方点向除了u以外的点连边,让那些点成为它儿子

然后认u为爸爸,因为u可能还会是其他方点的儿子,这样就可以联通上了

而其他点不可能再成为其它方点的儿子了(dfs树的性质)

代码如下:

void tarjan(int u,int fa){
    dfn[u]=low[u]=++tim1;s[++topp]=u;
    for (int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if (v==fa) continue;
        if (!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if (low[v]>=dfn[u]){//说明u是割点,v所在的点双到u为止,u以上的都不能在这个点双内 
                cnt++;G[u].push_back(cnt);
                while (s[topp]!=v){
                    G[cnt].push_back(s[topp]);
                    S[cnt].insert(w[s[topp]]);
                    topp--;
                }
                G[cnt].push_back(s[topp]);
                S[cnt].insert(w[s[topp]]);
                topp--;
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}

上述代码的S是因为后面的例题UOJ30

 

例题UOJ30

有一个性质叫做,x和y能遍历的点,等于圆方树上x到y的路径上的信息

其中方点维护所有和它连边的圆点的信息

然后这道题,我们发现如果方点直接维护所有和它连边的信息会有问题

修改的时候如果一个点有多个儿子是方点就自爆了(O(n)修改了)

所以这里方点只维护所有儿子圆点的信息

这样修改的话只要修改自己,和自己的父亲方点的信息

查询的时候,如果lca是方点那么把答案再加上fa[lca],就是这个答案

代码如下:

#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int sz[N],head[N],heavyson[N],top[N],dfn[N],low[N],d[N];char ss[5];
int rel[N],id[N],father[N],w[N],s[N],dep[N],n,m,Q,x,y,topp,kk,tim1,cnt;
vector<int>G[N];
multiset<int>S[N];
struct Edge{int nxt,to;}e[N];
inline void link(int x,int y){e[++kk].nxt=head[x];e[kk].to=y;head[x]=kk;}
void tarjan(int u,int fa){
    dfn[u]=low[u]=++tim1;s[++topp]=u;
    for (int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if (v==fa) continue;
        if (!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if (low[v]>=dfn[u]){//说明u是割点,v所在的点双到u为止,u以上的都不能在这个点双内 
                cnt++;G[u].push_back(cnt);
                while (s[topp]!=v){
                    G[cnt].push_back(s[topp]);
                    S[cnt].insert(w[s[topp]]);
                    topp--;
                }
                G[cnt].push_back(s[topp]);
                S[cnt].insert(w[s[topp]]);
                topp--;
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
void dfs1(int u,int fa){
    sz[u]=1;
    for (int i=0;i<(int)G[u].size();i++){
        int v=G[u][i];
        if (v==fa) continue;
        dep[v]=dep[u]+1;
        father[v]=u;
        dfs1(v,u);
        sz[u]+=sz[v];
        if (!heavyson[u]||sz[v]>sz[heavyson[u]]) heavyson[u]=v;
    }
}
void dfs2(int u,int first){
    top[u]=first;id[u]=++tim1;
    rel[tim1]=u;
    if (!heavyson[u]) return;
    dfs2(heavyson[u],first);
    for (int i=0;i<(int)G[u].size();i++){
        int v=G[u][i];
        if (v==father[u]||v==heavyson[u]) continue;
        dfs2(v,v);
    }
}
inline int lca(int x,int y){
    while (top[x]!=top[y]){
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        x=father[top[x]];
    }
    if (dep[x]<dep[y]) return x;return y;
}
void build(int k,int l,int r){
    if (l==r){
        int x=rel[l];
        if (x>n) d[k]=*S[x].begin();
        else d[k]=w[x];
        return;
    }
    int mid=(l+r)>>1;
    build(k*2,l,mid);build(k*2+1,mid+1,r);
    d[k]=min(d[k*2],d[k*2+1]);
}
void update(int k,int l,int r,int x,int y){
    if (l==r){d[k]=y;return;}
    int mid=(l+r)>>1;
    if (x<=mid) update(k*2,l,mid,x,y);
    else update(k*2+1,mid+1,r,x,y);
    d[k]=min(d[k*2],d[k*2+1]);
}
void update1(int k,int l,int r,int x,int y,int z){
    if (l==r){
        int u=rel[l];
        S[u].erase(S[u].find(y));
        S[u].insert(z);
        int mn=*S[u].begin();
        update(1,1,cnt,id[u],mn);
        return;
    }
    int mid=(l+r)>>1;
    if (x<=mid) update1(k*2,l,mid,x,y,z);
    else update1(k*2+1,mid+1,r,x,y,z);
    d[k]=min(d[k*2],d[k*2+1]);
}
int getpos(int k,int l,int r,int x){
    if (l==r) return d[k];
    int mid=(l+r)>>1;
    if (x<=mid) return getpos(k*2,l,mid,x);
    else return getpos(k*2+1,mid+1,r,x);
}
int query(int k,int l,int r,int x,int y){
    if (x<=l&&y>=r) return d[k];
    int mid=(l+r)>>1;
    if (y<=mid) return query(k*2,l,mid,x,y);
    else if (x>mid) return query(k*2+1,mid+1,r,x,y);
    else return min(query(k*2,l,mid,x,mid),query(k*2+1,mid+1,r,mid+1,y));
}
int Query(int x,int y){
    int ans=1e9;
    while (top[x]!=top[y]){
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        ans=min(ans,query(1,1,cnt,id[top[x]],id[x]));
        x=father[top[x]];
    }
    if (dep[x]<dep[y]) swap(x,y);
    ans=min(ans,query(1,1,cnt,id[y],id[x]));
    return ans;
}
int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for (int i=1;i<=n;i++) scanf("%d",&w[i]);
    for (int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        link(x,y);link(y,x);
    }
    cnt=n;tarjan(1,-1);tim1=0;
    dfs1(1,-1);dfs2(1,1);
    build(1,1,cnt);
    while (Q--){
        scanf("%s%d%d",ss+1,&x,&y);
        if (ss[1]=='C'){
            update(1,1,cnt,id[x],y);
            if (father[x]>n) update1(1,1,cnt,id[father[x]],w[x],y);
            w[x]=y;
        }
        else {
            int LCA=lca(x,y);
            int ans=1e9;
            if (LCA>n&&father[LCA]) ans=getpos(1,1,cnt,id[father[LCA]]);
            ans=min(ans,Query(x,y));
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

posted @ 2018-09-12 15:01  longint  阅读(290)  评论(0编辑  收藏  举报