codeforces 757F

最短路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; }

 

转载于:https://www.cnblogs.com/Mnirvana/p/8041887.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值