codeforces 757F
阿新 • • 發佈:2017-12-15
amp head fin return 新的 typedef sdi c++ bits
最短路DAG + 支配樹
支配樹是一種解決必經點問題的數據結構。
在dijkstra中可以處理處拓撲序,進而建立最短路DAG
但由於求最短路時,可能會有未聯通的點,所以在用最短路求拓撲序的時候,要把被更新的點pop掉。
附代碼
#include "bits/stdc++.h"
using namespace std;
#define maxn 2222222
#define For(i ,j ,n) for(int i = j; i<=n; i++)
#define pa pair<long long ,int>
int n ,m ,s ,head[maxn] ,deep[maxn] ,cnt ,ord[maxn],size[maxn] ,p[maxn][22] ,maxx;
bool vis[maxn];
long long dis[maxn];
typedef long long ll;
vector <pair<int, ll> > e[maxn];
template <typename T>
void read(T &x)
{
x = 0;char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c))
{
x = (x<<3) + (x<<1) + c - ‘0‘;
c = getchar();
}
return ;
}
const long long inf = 1ll<<60;
void dijkstra()
{
set <pair<ll, int> > hs;
for(int i=1; i<=n; i++)
dis[i] = inf;
dis[s] = 0;
for(int i=1; i<=n ;i++) hs.insert(make_pair(dis[i], i));
for(int i=0; i<n; i++)
{
int u = (hs.begin())->second; hs.erase(hs.begin());
ord[i] = u;
for(int j = 0; j < e[u].size(); j++)
{
int v = e[u][j].first;
if(dis[e[u][j].first] > dis[u]+e[u][j].second)
{
hs.erase(make_pair(dis[v], v));
dis[e[u][j].first] = dis[u]+e[u][j].second;
hs.insert(make_pair(dis[v], v));
}
}
}
}
int lca(int a, int b)
{
if(deep[a] < deep[b]) swap(a ,b);
if(deep[a] != deep[b])
{
for(int i=20; i>=0; i--)
if(deep[p[a][i]] >= deep[b])
a = p[a][i];
}
if(a == b) return a;
for(int i=20; i>=0; i--)
if(p[a][i] != p[b][i])
{
a = p[a][i];
b = p[b][i];
}
return p[a][0];
}
int main()
{
cin >>n >>m >>s;
int a ,b ,c;
For(i ,1 ,m)
{
cin>>a>>b>>c;
e[a].push_back(make_pair(b, c));
e[b].push_back(make_pair(a, c));
}
dijkstra();
p[s][0] = 0;deep[s] = 1;
for(int i = 1; i <= n; i++)
{
int d = -1, u = ord[i];
for(vector<pair<int ,long long> >::iterator iter = e[u].begin();iter!=e[u].end();iter++)
{
if(dis[iter->first] + iter->second == dis[u])
{
if(d == -1) d = iter->first;
else d = lca(d, iter->first);
}
}
p[u][0] = d; deep[u] = deep[d]+1;
for(int j = 1; j < 21; j++) p[u][j] = p[p[u][j-1]][j-1]; //動態更新公共祖先
}
for(int i = 1; i <= n; i++) size[i] = 1;
int ret = 0;
for(int i = n-1; i >= 1; i--) //按照拓撲序dp求最大值
{
int u = ord[i];
size[p[u][0]] += size[u];
if(dis[u] <= (1ll<<50)) ret = max(ret, size[u]);
}
for(int i=1; i<=n; i++)
cout <<ord[i] <<" ";
cout <<ret <<endl;
}
codeforces 757F