graph/leave.(二进制分组,多起点spfa)
二进制枚举,把所有的和1相连的点分成两组,一组为起点,一组为终点=。=
把所有起点一起跑spfa。注意重边。我用了双向队列,优化一波=、=
#include<bits/stdc++.h>
using namespace std;
int n,m;
int tp, nex[200005], tov[200005], h[200005];
int head, tail, vis[200005];
long long tow[200005],dis[200005], ans = 1e18;
deque<long long> q;
void read(int &x)
{
x = 0; int ff = 0; char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') ff = 1; c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0'; c = getchar();
}
if(ff) x = -x;
}
void add(int x,int y,int w)
{
tp++;
tow[tp] = w;
tov[tp] = y;
nex[tp] = h[x];
h[x] = tp;
}
/*void spfa()
{
while(head < tail)
{
head++;
int x = q[head];
for(int i = h[x]; i; i = nex[i])
{
int v = tov[i];
if(dis[v] > dis[x] + tow[i] && v != 1)
{
dis[v] = dis[x] + tow[i];
if(vis[v] == 0)
{
vis[v] = 1;
tail++;
q[tail] = v;
}
}
}
vis[x] = 0;
}
}*/
void spfa()
{
while(q.size())
{
int x = q.front();
q.pop_front();
for(register int i = h[x]; i; i = nex[i])
{
int v = tov[i];
if(dis[v] > dis[x] + tow[i] && v != 1)
{
dis[v] = dis[x] + tow[i];
if(vis[v] == 0)
{
vis[v] = 1;
if(!q.size()||dis[q.front()] < dis[v]) q.push_back(v);
else q.push_front(v);
}
}
}
vis[x] = 0;
}
}
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
read(n); read(m);
for(register int i = 1; i <= m; i++)
{
int u,v,a,b;
read(u); read(v); read(a); read(b);
add(u,v,a);
add(v,u,b);
}
int he = n, wei = 0;
while(1)
{
memset(vis,0,sizeof(vis));
for(register int i = 1; i <= n; i++)
dis[i] = 1e9;
head = 0 ;tail = 0;
for(register int i = h[1]; i; i = nex[i])
{
int v =tov[i];
if((v >> wei) & 1)
{
tail++;
dis[v] = min(dis[v],tow[i]);
vis[v] = 1;
/*tail++;
q[tail] = v;*/
q.push_front(v);
}
}
if(tail != n-1)
{
spfa();
for(register int j = h[1]; j ; j = nex[j])
{
int vv = tov[j];
if(((vv >> wei) & 1) == 0)
for(register int i = h[vv]; i; i = nex[i])
{
int v =tov[i];
if(v == 1)
{
if(dis[vv] + tow[i] < ans) ans = dis[vv] + tow[i];
}
}
}
}
memset(vis,0,sizeof(vis));
for(register int i = 1; i <= n; i++)
dis[i] = 1e9;
head = 0 ;tail = 0;
for(register int i = h[1]; i; i = nex[i])
{
int v =tov[i];
if(((v >> wei) & 1) == 0)
{ tail++;
vis[v] = 1;
dis[v] = min(dis[v],tow[i]);
q.push_front(v);
}
}
if(tail != n-1)
{
spfa();
for(register int j = h[1]; j ; j = nex[j])
{
int vv = tov[j];
if((vv >> wei) & 1)
for(register int i = h[vv]; i; i = nex[i])
{
int v =tov[i];
if(v == 1)
{
if(dis[vv] + tow[i] < ans)ans = dis[vv] + tow[i];
}
}
}
}
if(he == 0) break;
he >>= 1;wei++;
}
printf("%lld",ans);
return 0;
}