1 条题解
-
1
支配树。
先跑出最短路,建出最短路的 DAG,然后再 DAG 上删掉一个点,使得原先与起点联通,后来不连通的数量最大。
直接建立支配树,每个节点代表如果删掉这个点,这个点为根的子树中所有的点的最短路都会改变。
考虑建立这颗树,每次加入一个点的时候,考虑这个点挂在那个节点上。
如果 DAG 上所有连向 的点都改变了,那么 的最短路也会改变,所以 必然挂在这些点的 LCA 上。
所以加边的顺序就是拓扑序,这样可以保证连向 的点已经在树上了。
最后找一个最大的子树就好了。
代码
#include<bits/stdc++.h> #define mp make_pair #define int long long using namespace std; typedef pair<int,int> Int; const int N=2e5+5; int dis[N],vis[N],p[N],tot,n,m,dep[N],siz[N],s,rd[N],f[N][30]; vector<int> e1[N],e2[N],tr[N]; vector<Int> e[N]; void dij(){ priority_queue<Int,vector<Int>,greater<Int> > q; memset(dis,10,sizeof(dis)); dis[s]=0; q.push(mp(0,s)); while(!q.empty()){ int x=q.top().second; q.pop(); if(vis[x])continue; vis[x]=1; for(auto i:e[x]){ int y=i.first,z=i.second; if(dis[x]+z<dis[y]){ dis[y]=dis[x]+z; q.push(mp(dis[y],y)); } } } } void topsort(){ queue<int> q; q.push(s); while(!q.empty()){ int x=q.front(); p[++tot]=x; q.pop(); for(int y:e1[x]){ rd[y]--; if(!rd[y])q.push(y); } } } void dfs(int x,int fa){ siz[x]=1; for(int y:tr[x]){ if(y==fa)continue; dfs(y,x); siz[x]+=siz[y]; } } int lca(int x,int y){ if(dep[x]>dep[y])swap(x,y); for(int i=20;i>=0;i--)if(dep[f[y][i]]>=dep[x])y=f[y][i]; if(x==y)return x; for(int i=20;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } signed main(){ scanf("%lld%lld%lld",&n,&m,&s); for(int i=1,x,y,z;i<=m;i++){ scanf("%lld%lld%lld",&x,&y,&z); e[x].push_back(mp(y,z)); e[y].push_back(mp(x,z)); } dij(); for(int x=1;x<=n;x++) for(auto i:e[x]){ int y=i.first,z=i.second; if(dis[y]+z==dis[x])e1[y].push_back(x),e2[x].push_back(y),rd[x]++; } topsort(); dep[s]=1; for(int i=2;i<=tot;i++){ int x=p[i]; int Fa=e2[x][0]; for(int y:e2[x])Fa=lca(Fa,y); tr[Fa].push_back(x); dep[x]=dep[Fa]+1; f[x][0]=Fa; for(int j=1;j<=20;j++)f[x][j]=f[f[x][j-1]][j-1]; } dfs(s,0); int ans=0; for(int i=1;i<=n;i++)if(i!=s)ans=max(ans,siz[i]); printf("%lld",ans); }
- 1
信息
- ID
- 68
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- (无)
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者