图论笔记
圆方树
圆方树就是用 tarjan 跑出图中的所有点双,然后新建节点表示这个点双,分别与上面的割点和点双里的所有点连边,记得开二倍空间
这个题只有一次询问,所以就建完数判定一下两个点是否可达以及中间有没有原点即可
#include<bits/stdc++.h>
#define N 400005
using namespace std;
vector<int>y[N],w[N];
stack<int>Q;
int dfn[N],low[N],top=0,tot=0,fa[N],dep[N];
void tarjan(int u){
Q.push(u);
dfn[u]=low[u]=++top;
for(int i=0;i<y[u].size();i++){
if(dfn[y[u][i]]){
low[u]=min(low[u],dfn[y[u][i]]);
continue;
}
tarjan(y[u][i]);
low[u]=min(low[u],low[y[u][i]]);
if(low[y[u][i]]>=dfn[u]){
tot++;
w[tot].push_back(u);
w[u].push_back(tot);
while(Q.top()!=y[u][i]){
w[Q.top()].push_back(tot);
w[tot].push_back(Q.top());
Q.pop();
}
w[Q.top()].push_back(tot);
w[tot].push_back(Q.top());
Q.pop();
}
}
return;
}
void dfs(int u,int Fa){
dep[u]=dep[Fa]+1;
fa[u]=Fa;
for(int i=0;i<w[u].size();i++)if(w[u][i]!=Fa)dfs(w[u][i],u);
return;
}
signed main(){
int n;
scanf("%d",&n);
tot=n;
int u,v;
scanf("%d%d",&u,&v);
while(u&&v){
y[u].push_back(v);
y[v].push_back(u);
scanf("%d%d",&u,&v);
}
scanf("%d%d",&u,&v);
tarjan(u);
while(!Q.empty()){
w[u].push_back(Q.top());
w[Q.top()].push_back(u);
Q.pop();
}
dfs(u,0);
if(!dfn[v]){
printf("No solution\n");
return 0;
}
int ans=n+1;
v=fa[v];
if(u==v){
printf("No solution\n");
return 0;
}
while(v!=u){
if(v<=n)ans=min(ans,v);
v=fa[v];
}
if(ans<=n)printf("%d\n",ans);
else printf("No solution\n");
return 0;
}
这个麻烦点,需要搞出给定点的集合之间的所有路径,说白了就是建完虚树后所有的非选定点有多少是圆点
#include<bits/stdc++.h>
#define N 400005
using namespace std;
vector<int>y[N],w[N];
stack<int>Q;
int dfn[N],low[N],top=0,tot=0,dep[N],fa[N][22],dis[N][21],x[N],L[N],R[N],cnt=0,vis[N],f[N],used[N],n,m;
void tarjan(int u){
dfn[u]=low[u]=++top;
Q.push(u);
for(int i=0;i<y[u].size();i++){
if(dfn[y[u][i]]){
low[u]=min(low[u],dfn[y[u][i]]);
continue;
}
tarjan(y[u][i]);
low[u]=min(low[u],low[y[u][i]]);
if(low[y[u][i]]>=dfn[u]){
tot++;
w[tot].push_back(u);
w[u].push_back(tot);
while(Q.top()!=y[u][i]){
w[Q.top()].push_back(tot);
w[tot].push_back(Q.top());
Q.pop();
}
w[Q.top()].push_back(tot);
w[tot].push_back(Q.top());
Q.pop();
}
}
return;
}
void dfs(int u,int Fa){
dep[u]=dep[Fa]+1;
fa[u][0]=Fa;
if(Fa&&Fa<=n)dis[u][0]=1;
L[u]=++cnt;
for(int i=0;i<w[u].size();i++)if(w[u][i]!=Fa)dfs(w[u][i],u);
R[u]=cnt;
return;
}
int DEP(int u,int v){
int go=dep[u]-dep[v];
for(int i=19;i>=0;i--)if(go&(1<<i))u=fa[u][i];
return u;
}
int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
u=DEP(u,v);
if(u==v)return u;
for(int i=19;i>=0;i--)if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
return fa[u][0];
}
bool cmp(int u,int v){return L[u]<L[v];}
signed main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
tot=n;
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
y[u].push_back(v);
y[v].push_back(u);
}
tarjan(1);
dfs(1,0);
dis[1][0]=0;
for(int i=1;i<=19;i++)for(int j=1;j<=tot;j++){
fa[j][i]=fa[fa[j][i-1]][i-1];
dis[j][i]=dis[j][i-1]+dis[fa[j][i-1]][i-1];
}
int q;
scanf("%d",&q);
while(q--){
int k;
scanf("%d",&k);
for(int i=1;i<=k;i++)scanf("%d",&x[i]);
sort(x+1,x+k+1,cmp);
for(int i=1;i<=k;i++)vis[i]=x[i];
for(int i=1;i<k;i++)vis[k+i]=LCA(x[i],x[i+1]);
sort(vis+1,vis+k*2,cmp);
int num=unique(vis+1,vis+k*2)-vis-1;
int now=1;
for(int i=2;i<=num;i++){
while(R[vis[now]]<L[vis[i]])now=f[now];
f[i]=now;
now=i;
}
int ans=0;
for(int i=2;i<=num;i++){
int go=dep[vis[i]]-dep[vis[f[i]]]-1;
int u=vis[i];
for(int j=19;j>=0;j--)if(go&(1<<j)){
ans+=dis[u][j];
u=fa[u][j];
}
}
for(int i=1;i<=k;i++)used[x[i]]=1;
for(int i=1;i<=num;i++)if(!used[vis[i]]&&vis[i]<=n)ans++;
for(int i=1;i<=k;i++)used[x[i]]=0;
printf("%d\n",ans);
}
for(int i=1;i<=tot;i++){
for(int j=0;j<=19;j++)fa[i][j]=dis[i][j]=0;
dfn[i]=low[i]=dep[i]=x[i]=L[i]=R[i]=vis[i]=f[i]=used[i]=0;
w[i].clear();
y[i].clear();
}
top=tot=cnt=0;
while(!Q.empty())Q.pop();
}
return 0;
}

浙公网安备 33010602011771号