点双学习
学了一下点双和圆方树
感觉圆方树好妙啊
大概就是说还是类似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; }