8/15 缩点+割点(割顶)+桥(割边)+字符串哈希
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了8/15 缩点+割点(割顶)+桥(割边)+字符串哈希相关的知识,希望对你有一定的参考价值。
P3387 【模板】缩点
分三部分:
1.使用tarjan缩点,将各个强连通分量(分量内各店可相互到达)看作一个点。
2.建立缩点后的拓扑图,这些连通分量间也存在连线。
3.由于tarjan的出栈操作,当dfn==low是出栈被标记,标记值是由小到大的。先被标记的值小。
因此要在拓扑图上逆序dp
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
using namespace std;
const int N=7e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
vector<int>e[N],ne[N];
int dfn[N],low[N],tot;
int stk[N],instk[N],top;
int scc[N],siz[N],cnt;
int n,m,a[N],val[N],dp[N];
void tarjan(int x)
//盖戳、入栈
dfn[x]=low[x]=++tot;
stk[++top]=x,instk[x]=1;
for(int y:e[x])
if(!dfn[y])
tarjan(y);
//回x时及时更新low
low[x]=min(low[x],low[y]);
else if(instk[y]) //若x已访问且在栈中
low[x]=min(low[x],dfn[y]);
if(dfn[x]==low[x]) //若x时SCC的根
int y;++cnt;
do
y=stk[top--];instk[y]=0; //出栈
scc[y]=cnt; //SCC编号
++siz[cnt];
val[cnt]+=a[y];
while(y!=x);
void solve()
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
int u,v;cin>>u>>v;
e[u].push_back(v);
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
//建立拓扑图
for(int i=1;i<=n;i++)
for(int j:e[i])
int a=scc[i],b=scc[j];
if(a!=b) ne[a].push_back(b);
//在拓扑图上逆序dp
for(int x=cnt;x;x--)
if(dp[x]==0) dp[x]=val[x];
for(int y:ne[x])
dp[y]=max(dp[y],dp[x]+val[y]);
int ans=0;
for(int i=1;i<=cnt;i++)
ans=max(ans,dp[i]);
cout<<ans<<endl;
signed main()
solve();
return 0;
P3388 【模板】割点(割顶)
割点判定法则: low[y]>=dfn[x]
非根结点找到一颗子树,根节点至少需要两棵子树。
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
using namespace std;
const int N=7e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
vector<int>e[N];
int dfn[N],low[N],tot;
int stk[N],instk[N],top;
int cut[N],root;
int n,m;
void tarjan(int x)
//盖戳、入栈
dfn[x]=low[x]=++tot;
int child=0;
for(int y:e[x])
if(!dfn[y])
tarjan(y);
//回x时及时更新low,判断割点
low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x])
child++;
if(x!=root||child>1)
cut[x]=1;
else
low[x]=min(low[x],dfn[y]);
void solve()
cin>>n>>m;
for(int i=1;i<=m;i++)
int u,v;cin>>u>>v;
e[u].push_back(v),e[v].push_back(u);
for(int i=1;i<=n;i++)
if(!dfn[i])
root=i,tarjan(i);
int ans=0;
for(int i=1;i<=n;i++)
if(cut[i]) ans++;
cout<<ans<<endl;
for(int i=1;i<=n;i++)
if(cut[i]) cout<<i<<" ";
cout<<endl;
signed main()
solve();
return 0;
割边
https://www.bilibili.com/video/BV14g411Q7ze?spm_id_from=333.999.0.0&vd_source=91973ada1213cf6ba2cbb43a2bebd2e8
条件:low[y]>dfn[x]
不允许走x->y的反边更新low值
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
#define ULL unsigned long long
using namespace std;
const int N=7e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
const int P=131;
struct edge
int to,nxt;
e[N]; //边集
int dfn[N],low[N],tot,cnt,idx=1;
struct bridge
int x,y;
bri[N];
void add(int to,int nxt)
e[++idx]=to,head[from];
h[from]=idx;
void tarjan(int x,int in_edge)
dfn[x]=low[x]=++tot;
for(int i=head[x];i;i=e[i].nxt)
int y=e[i].to;
if(!dfn[y])
tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
bri[++cnt]=x,y;
else if(i!=(in_edge^1))
low[x]=min(low[x],dfn[y]);
void solve()
signed main()
solve();
return 0;
P7687 [CEOI2005] Critical Network Lines
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
#define ULL unsigned long long
using namespace std;
const int N=7e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
const int P=131;
struct edge
int to,nxt;
e[N]; //边集
int dfn[N],low[N],tot,cnt,idx=1,head[N],a[N],b[N],n,m,k,l;
struct bridge
int x,y;
bri[N];
void add(int from,int to)
e[++idx]=to,head[from];
head[from]=idx;
void tarjan(int x,int in_edge)
dfn[x]=low[x]=++tot;
for(int i=head[x];i;i=e[i].nxt)
int y=e[i].to;
if(!dfn[y])
tarjan(y,i);
low[x]=min(low[x],low[y]);
if(low[y]>dfn[x])
if(!a[y]||!b[y]||a[y]==k||b[y]==l)
bri[++cnt]=x,y;
a[x]+=a[y],b[x]+=b[y];
else if(i!=(in_edge^1))
low[x]=min(low[x],dfn[y]);
void solve()
cin>>n>>m>>k>>l;
for(int i=1,x;i<=k;i++)
cin>>x,a[x]=1;
for(int i=1,x;i<=l;i++)
cin>>x,b[x]=1;
for(int i=1,u,v;i<=m;i++)
cin>>u>>v;add(u,v),add(v,u);
tarjan(1,2);
cout<<cnt<<endl;
for(int i=1;i<=cnt;i++)
cout<<bri[i].x<<" "<<bri[i].y<<endl;
signed main()
solve();
return 0;
字符串哈希
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define maxn 1000000000LL
#define ULL unsigned long long
using namespace std;
const int N=7e5以上是关于8/15 缩点+割点(割顶)+桥(割边)+字符串哈希的主要内容,如果未能解决你的问题,请参考以下文章