Tarjan割边
深度优先遍历时从一条边进入这个点,不能从这条边回去
板子
例题:删边问题【蓝桥杯】
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
ll dfn[200005],low[200005],tot;
ll w[200005],cnt,ans=0x3f3f3f3f3f3f3f3f,sum;
vector<PII> e;
vector<ll> h[200005];
bool flag=0;
void add(ll a,ll b)
{
e.push_back({a,b});
//让两个点之间边编号,第二个编号就是反向的,便于后面判断
h[a].push_back(e.size()-1);
}
void tarjan(ll x,ll in_edg)
{
dfn[x]=low[x]=++tot;
for(ll i=0;i<h[x].size();i++)
{
ll j=h[x][i];
ll y=e[j].second;
if(!dfn[y])
{
tarjan(y,j);
low[x]=min(low[y],low[x]);
w[x]+=w[y];
if(low[y]>dfn[x])
{
ans=min(ans,llabs(sum-2*w[y]));
flag=1;
}
}
//不是反向边
else if(j!=(in_edg^1)) low[x]=min(low[x],dfn[y]);
}
}
int main()
{
ll n,m;
cin>>n>>m;
for(ll i=1;i<=n;i++)
{
cin>>w[i];
sum+=w[i];
}
for(ll i=0;i<m;i++)
{
ll u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
tarjan(1,0);
if(w[1]!=sum) cout<<llabs(sum-2*w[1])<<endl;
else if(flag) cout<<ans<<endl;
else cout<<-1<<endl;
return 0;
}