CF1051F The Shortest Statement

题目大意:给出n个点和m条边,其中n<=1e5,m-n<=20,q次询问,询问两点最短路。

题解:由于m-n<=20,所以可以当树上套环来做。先用最小生成树开一棵树,然后对于每个删掉的边的节点跑dij。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
#define ll long long
ll n,m,q;
struct node
{
    ll u,c,v;
}p[N];
bool cmp(node a,node b)
{
    return a.v<b.v;
}
ll fa[N];
ll findfa(ll x)
{
    if(fa[x]==x)return x;
    return fa[x] = findfa(fa[x]);
}
ll hed[N],cnt,hed2[N],cnt2;
ll luk[N],dis[50][N],tk;
struct EG
{
    ll to,val,nxt;
}e[2*N],e2[2*N];
void ae(ll f,ll t,ll v)
{
    e[++cnt].to = t;
    e[cnt].val = v;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
void ae2(ll f,ll t,ll v)
{
    e2[++cnt2].to = t;
    e2[cnt2].val = v;
    e2[cnt2].nxt = hed2[f];
    hed2[f] = cnt2;
}
ll dep[N],ds[N],ff[N],tp[N],siz[N],son[N];
void dfs1(ll u,ll f)
{
    siz[u]=1;
    dep[u]=dep[f]+1;
    for(ll j=hed[u];j;j=e[j].nxt)
    {
        ll to = e[j].to;
        if(to==f)continue;
        ff[to]=u;
        ds[to]=ds[u]+e[j].val;
        dfs1(to,u);
        siz[u]+=siz[to];
        if(siz[to]>siz[son[u]])son[u]=to;
    }
}
void dfs2(ll u,ll tu)
{
    tp[u]=tu;
    if(!son[u])return ;
    dfs2(son[u],tu);
    for(ll j=hed[u];j;j=e[j].nxt)
    {
        ll to = e[j].to;
        if(to==ff[u]||to==son[u])continue;
        dfs2(to,to);
    }
}
ll get_lca(ll x,ll y)
{
    while(tp[x]!=tp[y])
    {
        if(dep[tp[x]]<dep[tp[y]])swap(x,y);
        x=ff[tp[x]];
    }
    return dep[x]<dep[y]?x:y;
}
ll get_dis(ll x,ll y)
{
    return ds[x]+ds[y]-2*ds[get_lca(x,y)];
}
struct nd
{
    ll x,d;
    nd(){}
    nd(ll x,ll d):x(x),d(d){}
    friend bool operator < (nd a,nd b)
    {
        return a.d>b.d;
    }
}tpp;
priority_queue<nd>que;
bool vis[N];
void dij(ll x)
{
    memset(vis,0,sizeof(vis));
    dis[x][luk[x]]=0;
    que.push(nd(luk[x],0));
    while(!que.empty())
    {
        tpp = que.top();
        que.pop();
        ll u = tpp.x;
        if(vis[u])continue;
        vis[u]=1;
        for(ll j=hed2[u];j;j=e2[j].nxt)
        {
            ll to = e2[j].to;
            if(dis[x][to]>dis[x][u]+e2[j].val)
            {
                dis[x][to] = dis[x][u]+e2[j].val;
                que.push(nd(to,dis[x][to]));
            }
        }
    }
}
/*void fkstl()
{
    int tmp[N]={-1,0},len=0;
    for(int i=1;i<=tk;i++)
        if(tmp[len]!=luk[i])
            tmp[++len] = luk[i];
    tk = len;
    for(int i=1;i<=tk;i++)
        luk[i]=tmp[i];
}*/
inline ll read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    n=read(),m=read();
    for(ll u,c,v,i=1;i<=m;i++)
    {
        u=read(),c=read(),v=read();
        p[i].u=u,p[i].c=c,p[i].v=v;
        ae2(u,c,v),ae2(c,u,v);
    }
    sort(p+1,p+1+m,cmp);
    for(ll i=1;i<=n;i++)fa[i]=i;
    ll tot = 0;
    for(ll i=1;i<=m;i++)
    {
        ll u = p[i].u,c = p[i].c;
        ll f1 = findfa(u),f2 = findfa(c);
        if(f1!=f2)
        {
            ae(u,c,p[i].v);ae(c,u,p[i].v);
            fa[f1]=f2;
            tot++;
        }else
        {
            luk[++tk]=u;
            luk[++tk]=c;
        }
    }
    ll rt = findfa(1);
    dfs1(rt,0);dfs2(rt,rt);
    sort(luk+1,luk+1+tk);
    tk = unique(luk+1,luk+1+tk)-(luk+1);
//    fkstl();
    memset(dis,0x7f,sizeof(dis));
    for(ll i=1;i<=tk;i++)
        dij(i);
    q=read();
    ll l,r;
    for(ll i=1;i<=q;i++)
    {
        l=read(),r=read();
        ll ans = get_dis(l,r);
        for(ll j=1;j<=tk;j++)
            ans = min(ans,dis[j][l]+dis[j][r]);
        printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9803971.html