题意:无向图中有n个点,m条边,现给你一个起点s。要求点u有:
- u!=s
- 原图中去掉u后改变的最短路最多
现有一种数据结构可以维护出在有向图中从起点到每个点的路径中的距离该点最近的必经点。
那么最短路图中每个必经点所控制的点的最大值就是我们所需要的答案。
这题的思路也就是这么简单,关键是学会支配树的基本用法。
做法:
- 首先维护出起点到每个点的最短路;
- 然后根据最短路画出最短路图;
- 然后对最短路图建树;
- 从后往前把当前点v的权值贡献给idom(v);
- 求出权值最大的点。
Upd:2019/7/29 加了个初始化dfn数组
#include<algorithm>
#include<vector>
#include<iostream>
#include<math.h>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
#include<queue>
#define qcin; ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
#define clr(x) memset(x,0,sizeof x)
#define fmax(x) memset(x,0x3f,sizeof x)
#define finit(x) memset(x,-1,sizeof x)
#define dis(l,r) r-l+1
#define gstr(str) scanf("%s",str)
#define glen(str) strlen(str)
using namespace std;
typedef long long ll;
namespace Input
{
const int BUF = 65536;
char buf[BUF + 1];
char *head = buf, *tail = buf;
}
inline char inputchar()
{
using namespace Input;
if(head == tail)
*(tail = (head = buf) + fread(buf, 1, BUF, stdin)) = 0;
return *head++;
}
inline void io(int &ret){
char ch = inputchar();
while(ch < '0' || ch > '9')
ch = inputchar();
ret = ch - '0';
ch = inputchar();
while(ch >= '0' && ch <= '9'){
ret = ret * 10 + ch - '0';
ch = inputchar();
}
}
inline void sio(int &ret){
ret = 0;
char ch = inputchar();
while((ch < '0' || ch > '9') && ch != '-')
ch = inputchar();
bool neg = false;
if(ch == '-')
neg = true, ch = inputchar();
while(ch >= '0' && ch <= '9')
{
ret = ret * 10 + ch - '0';
ch = inputchar();
}
if(neg)
ret = -ret;
}
typedef pair<ll,ll>pll;
const int maxn = 5e5+10;
const ll mod = 2148473648;
typedef ll arr[maxn];
typedef char str[maxn];
void file(int x){if(x&&fopen("in.txt","r")){freopen("in.txt","r",stdin);if(x==2)freopen("1.txt","w",stdout);}}
struct node{
int to,cst,nxt;
}E[maxn*10];
const double pi=acos(-1);
arr dfn,id,h,anc,sdom,idom,pre,dom,d,fa,best,H,num;
int n,tot,pos,m,st;
void addedge(ll h[],int u,int v,int w=0){
E[tot].to=v;
E[tot].cst=w;
E[tot].nxt=h[u];
h[u]=tot++;
}
void dfs(int x){
dfn[x]=++pos,id[pos]=x;
for(int i=h[x];~i;i=E[i].nxt){
int y=E[i].to;
if(!dfn[y]){
dfs(y);
fa[dfn[y]]=dfn[x];
}
}
}
int get(int x){
if(anc[x]==x)return x;
int y=get(anc[x]);
if(sdom[best[x]]>sdom[best[anc[x]]]){
best[x]=best[anc[x]];
}
anc[x]=y;
return y;
}
void tarjin(){
for(int y=pos;y>1;y--){
int x=fa[y];
int p=id[y];
for(int i=pre[p];~i;i=E[i].nxt){
int z=E[i].to;
z=dfn[z];
if(!z)continue;
get(z);
sdom[y]=min(sdom[y],sdom[best[z]]);
}
addedge(dom,sdom[y],y);
anc[y]=x;
for(int i=dom[x];~i;i=E[i].nxt){
int z=E[i].to;
get(z);
if(sdom[best[z]]<x)idom[z]=best[z];
else idom[z]=x;
}
dom[x]=-1;
}
for(int i=2;i<=pos;i++){
if(idom[i]!=sdom[i]){
idom[i]=idom[idom[i]];
}
addedge(dom,idom[i],i);
}
idom[1]=0;
}
void dij(int st){
fmax(d);
static int vis[maxn];
priority_queue<pll>Q;
d[st]=0;
Q.push(mp(0,st));
while(Q.size()){
int u=Q.top().second;
Q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=H[u];~i;i=E[i].nxt){
int v=E[i].to;
ll cost=d[u]+E[i].cst;
if(cost<d[v]){
d[v]=cost;
Q.push(mp(-cost,v));
}
}
}
}
void init(){
finit(dom);finit(H);finit(h);finit(pre);
clr(num);clr(dfn);
for(int i=0;i<=n;i++){
sdom[i]=anc[i]=best[i]=i;
}
tot=0;
pos=0;
}
int main(){
file(1);
int u,v,w;
io(n),io(m),io(st);
init();
while(m--){
io(u),io(v),io(w);
addedge(H,u,v,w);
addedge(H,v,u,w);
}
dij(st);
for(int u=1;u<=n;u++){
for(int i=H[u];~i;i=E[i].nxt){
int v=E[i].to;
if (d[u]+E[i].cst==d[v]){
addedge(h,u,v);
addedge(pre,v,u);
}
}
}
dfs(st);
tarjin();
int ans=0;
for(int i=pos;i>1;i--){
num[i]++;
num[idom[i]]+=num[i];
ans=max((ll)ans,num[i]);
}
printf("%d\n",ans);
return 0;
}