法 - 分类讨论

题目大意:
给一张无向图求两两点间的最短路。 m ≤ n + 300 , n ≤ 1 0 5 m\le n+300,n\le10^5 mn+300,n105
题解:
考虑首先将度数为1的点删掉,每次删掉一个点就会影响这个点挂到的那个点出发的最短路次数。
然后问题转为在一张所有点度数大于1的图上求两两点最短路,并且每条最短路都要乘以两端的次数。
首先注意到 ∑ d = 2 m ⇒ ∑ ( d − 2 ) = 2 ( m − n ) ⇒ ∑ [ d > 2 ] ≤ 2 ( m − n ) \sum d=2m\Rightarrow\sum(d-2)=2(m-n)\Rightarrow\sum [d>2]\le2(m-n) d=2m(d2)=2(mn)[d>2]2(mn)
因此将所有度数大于等于3的点拿出来,不会很多;剩下的点其实就是连接这些关键点的若干条链。(若没有度数3的点就随便连个度数2的点和另外随意一个点即可)
然后继续注意到链的数量是 1 2 ∑ [ d > 2 ] d = 1 2 ( ∑ ( d − 2 ) + 2 ∑ [ d > 2 ] ) ≤ 3 ( m − n ) \frac 12\sum [d>2]d=\frac12\left(\sum(d-2)+2\sum[d>2]\right)\le3(m-n) 21[d>2]d=21((d2)+2[d>2])3(mn)
然后先求出一端是关键点的答案,直接bfs即可;
然后分两端在同一条链上,这个讨论一下可以前缀和;
然后两端不在同一条链上,这个就枚举一条链和一个不在链上的点,链上的点到这个点的答案可以一起算,还是可以前缀和。
然后就没了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
}using INPUT_SPACE::inn;
const int N=120000,M=N+300;
struct edges{
    int to,pre;
}e[M<<1];int h[N],etop,dgr[N],k[N];vector<int> g[N];
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
namespace DEL1{
    queue<int> q;int del[N],id[N],ks[N],d[N];
    inline pair<lint,int> del1(int n)
    {
        rep(i,1,n) ks[i]=1;lint ans=0;int y,cnt=0;
        rep(i,1,n) Rep(j,g[i]) g[i][j][d]++;
        rep(i,1,n) if(d[i]==1) q.push(i);//,debug(i)ln;
        while(!q.empty())
        {
            int x=q.front();q.pop(),del[x]=1;
            Rep(i,g[x]) if(!del[y=g[x][i]])
            {
                ans+=(lint)ks[x]*(n-ks[x]),ks[y]+=ks[x];
                if((--d[y])==1) q.push(y);
            }
        }
        rep(i,1,n) if(!del[i]) id[i]=++cnt,dgr[cnt]=d[i],k[cnt]=ks[i];
        rep(x,1,n) if(!del[x]) Rep(i,g[x])
            if(!del[y=g[x][i]]) add_edge(id[x],id[y]);
        return mp(ans,cnt);
    }
}
namespace SOLVE_space{
    queue<int> q;int vis[N],*d[N],dps[N<<1],isA[N];
    vector<int> lst,ls[N];int lsc,Lp[N],Rp[N],inls[N];
    inline int *newInt(int n) { int *p=new int[n];memset(p,0,sizeof(int)*n);return p; }
    inline lint bfs(int s,int n,int *d)
    {
        while(!q.empty()) q.pop();
        memset(vis,0,sizeof(int)*(n+1));
        q.push(s),d[s]=0,vis[s]=1;
        while(!q.empty())
        {
            int x=q.front();q.pop();
            for(int i=h[x],y;i;i=e[i].pre)
                if(!vis[y=e[i].to]) q.push(y),d[y]=d[x]+1,vis[y]=1;
        }
        lint ans=0;
        rep(i,1,n) if(isA[i]) ans+=(lint)k[i]*d[i];else ans+=2ll*k[i]*d[i];
        return ans;
    }
    lint _kps[N<<1],_kips[N<<1];
    inline lint kps(int l,int r) { return l<=r?_kps[r]-_kps[l-1]:0; }
    inline lint kips(int l,int r) { return l<=r?_kips[r]-_kips[l-1]:0; }
    inline lint solve(vector<int> &lst,int L,int R)
    {
    //  debug(L)sp,debug(R)sp,debug(lst.size())ln;Rep(i,lst) cerr<<lst[i]sp;cerr ln;debug(d[L][R])ln;
        int n=(int)lst.size();if(!n) return 0;n++;
        int dis=d[L][R];lint ans=0;int j=1;
        rep(i,1,n) dps[i]=dps[i-1]+1;
        dps[n+1]=dps[n]+dis;
        rep(i,n+2,2*n) dps[i]=dps[i-1]+1;
        rep(i,1,n-1) _kps[i]=_kps[i-1]+k[lst[i-1]],_kips[i]=_kips[i-1]+(lint)i*k[lst[i-1]];
        _kps[n]=_kps[n+1]=_kps[n-1],_kips[n]=_kips[n+1]=_kips[n-1];
        rep(i,n+2,2*n) _kps[i]=_kps[i-1]+k[lst[i-n-2]],_kips[i]=_kips[i-1]+(lint)i*k[lst[i-n-2]];
        rep(i,1,n-1)
        {
            j=max(i,j);lint res=0;
            while(j+1<i+n+1&&dps[j+1]-dps[i]<=dps[i+n+1]-dps[j+1]) j++;
        //  debug(i)sp,debug(j)ln;
            if(j<=n) res=kips(i+1,j)-i*kps(i+1,j)+(i+n+1)*kps(n+2,n+i)-kips(n+2,n+i)+(n+i+dis)*kps(j+1,n-1)-kips(j+1,n-1);
            //  debug(kips(i+1,j))sp,debug(i*kps(i+1,j))sp,debug((i+n+1)*kps(n+2,n+i))sp,debug((n+i+dis)*kps(j+1,n-1))sp,debug(kips(j+1,n-1))ln;
            else res=kips(i+1,n-1)-i*kps(i+1,n-1)+kips(n+2,j)+(dis-i-1)*kps(n+2,j)+(i+n+1)*kps(j+1,i+n)-kips(j+1,i+n);
            //  debug(kips(i+1,n-1))sp,debug(i*kps(i+1,n-1))sp,debug(kips(n+2,j))sp,debug((dis-i-1)*kps(n+2,j))sp,debug((i+n+1)*kps(j+1,i+n))sp,debug(kips(j+1,i+n))ln;
        //  debug(res)ln;
            ans+=k[lst[i-1]]*res;
        }
    //  debug(ans)ln;
        return ls[++lsc].swap(lst),Lp[lsc]=L,Rp[lsc]=R,ans;
    }
    inline int getnxt(int x,int y) { for(int i=h[x];i;i=e[i].pre) if(e[i].to^y) return e[i].to;return 0; }
    inline lint dfs(int x)
    {
        vis[x]=1;lint ans=0;
        for(int i=h[x],y;i;i=e[i].pre) if(!vis[y=e[i].to]&&!isA[e[i].to])
        {
            int z=y,zs,las=x;while(z&&!isA[z]) lst.pb(z),zs=z,z=getnxt(z,las),las=zs;
        //  debug(x)sp,debug(y)sp,debug(z)ln;
            if(!z) z=x;Rep(j,lst) lst[j][vis]=1;ans+=solve(lst,x,z);if(!vis[z]) ans+=dfs(z);
        }
        for(int i=h[x],y;i;i=e[i].pre) if(!vis[y=e[i].to]) ans+=dfs(y);
        return ans;
    }
    inline lint solve(vector<int> &ls,int L,int R,int n)
    {
        Rep(i,ls) ls[i][inls]=1;lint ans=0;int len=(int)ls.size()+1;
    //  debug(L)sp,debug(R)sp,debug(len)ln;
        rep(i,1,len-1) _kps[i]=_kps[i-1]+k[ls[i-1]],_kips[i]=_kips[i-1]+(lint)i*k[ls[i-1]];
        rep(x,1,n) if(!isA[x]&&!inls[x])
        {
            int Ld=d[L][x],Rd=d[R][x],p=(len+Rd-Ld)/2;p=max(p,0),p=min(p,len-1);
        //  debug(x)sp,debug(p)ln;
        //  debug(Ld)sp,debug(kps(1,p))sp,debug(kips(1,p))sp,debug((len+Rd)*kps(p+1,len-1))sp,debug(kips(p+1,len-1))ln;
            lint res=Ld*kps(1,p)+kips(1,p)+(len+Rd)*kps(p+1,len-1)-kips(p+1,len-1);
            ans+=res*k[x];
        }
    //  debug(ans)ln;
        Rep(i,ls) ls[i][inls]=0;return ans;
    }
    inline lint solve(int n)
    {
        if(n<=1) return 0;int mxdgr=0;rep(i,1,n) mxdgr=max(mxdgr,dgr[i]);
        if(mxdgr<=2) { int t=e[h[1]].to;dgr[1]++,dgr[t]++;add_edge(1,t),add_edge(t,1); }
        lint ans=0;rep(i,1,n) isA[i]=(dgr[i]>=3);
    //  rep(i,1,n) debug(i)sp,debug(dgr[i])sp,debug(k[i])ln;
        rep(i,1,n) if(isA[i]) d[i]=newInt(n+1),ans+=k[i]*bfs(i,n,d[i]);
    //  debug(ans)ln;
        memset(vis,0,sizeof(int)*(n+1));
        rep(i,1,n) if(isA[i]) { ans+=dfs(i);break; }
    //  debug(ans)ln;
        rep(i,1,lsc) ans+=solve(ls[i],Lp[i],Rp[i],n);
        return ans/2;
    }
}
int main()
{
//  freopen("data.in","r",stdin);
    int n=inn(),m=inn(),u,v;
    rep(i,1,m) u=inn(),v=inn(),(u!=v?g[u].pb(v),g[v].pb(u),0:0);
    pair<lint,int> delres=DEL1::del1(n);
    lint ans=delres.fir+SOLVE_space::solve(delres.sec);
    return !printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值