Luogu2993 FJOI2014 最短路径树问题 最短路树、长链剖分

传送门


强行二合一最为致命

第一问直接最短路+$DFS$解决

考虑第二问,与深度相关,可以考虑长链剖分。

设$f_{i,j}$表示长度为$i$,经过边数为$j$时的最大边权和,考虑到每一次从重儿子转移过来的时候,不仅要将$f$数组右移一格,还需要同时加上一个值。显然用线段树等数据结构额外维护是不现实的,我们考虑维护一个影响范围为整个$f_i$的加法标记$tag_i$,将$f_{i,0}$设置为$-tag_i$,每一次上传的时候把标记也一起上传,合并轻儿子、计算答案的时候将这个$tag$加上,就能够做到快速地维护了。

长链剖分代码比点分治还长……

  1 #include<bits/stdc++.h>
  2 #define P pair < int , int >
  3 #define int long long
  4 //This code is written by Itst
  5 using namespace std;
  6 
  7 inline int read(){
  8     int a = 0;
  9     bool f = 0;
 10     char c = getchar();
 11     while(c != EOF && !isdigit(c)){
 12         if(c == '-')
 13             f = 1;
 14         c = getchar();
 15     }
 16     while(c != EOF && isdigit(c)){
 17         a = (a << 3) + (a << 1) + (c ^ '0');
 18         c = getchar();
 19     }
 20     return f ? -a : a;
 21 }
 22 
 23 const int MAXN = 30010;
 24 vector < P > e[MAXN];
 25 struct edge{
 26     int end , upEd , w;
 27 }Ed[MAXN << 1];
 28 int dis[MAXN] , head[MAXN] , dep[MAXN] , len[MAXN] , md[MAXN] , son[MAXN] , f[MAXN << 1] , g[MAXN << 1] , sz[MAXN] , tag[MAXN] , *dp[MAXN] , *cnt[MAXN];
 29 int *p1 = f , *p2 = g , N , M , K , cntEd , ans , times;
 30 priority_queue < P > q;
 31 bool vis[MAXN];
 32 
 33 inline void addEd(int a , int b , int c){
 34     Ed[++cntEd].end = b;
 35     Ed[cntEd].upEd = head[a];
 36     Ed[cntEd].w = c;
 37     head[a] = cntEd;
 38 }
 39 
 40 void Dijk(){
 41     q.push(P(0 , 1));
 42     memset(dis , 0x3f , sizeof(dis));
 43     dis[1] = 0;
 44     while(!q.empty()){
 45         P t = q.top();
 46         q.pop();
 47         if(-t.first > dis[t.second])
 48             continue;
 49         for(int i = 0 ; i < sz[t.second] ; ++i)
 50             if(dis[e[t.second][i].first] > dis[t.second] + e[t.second][i].second){
 51                 dis[e[t.second][i].first] = dis[t.second] + e[t.second][i].second;
 52                 q.push(P(-dis[e[t.second][i].first] , e[t.second][i].first));
 53             }
 54     }
 55 }
 56 
 57 void create(int now){
 58     vis[now] = 1;
 59     for(int i = 0 ; i < sz[now] ; ++i)
 60         if(!vis[e[now][i].first] && dis[e[now][i].first] == dis[now] + e[now][i].second){
 61             addEd(now , e[now][i].first , e[now][i].second);
 62             addEd(e[now][i].first , now , e[now][i].second);
 63             create(e[now][i].first);
 64         }
 65 }
 66 
 67 void dfs1(int now , int pre){
 68     md[now] = dep[now] = dep[pre] + 1;
 69     for(int i = head[now] ; i ; i = Ed[i].upEd)
 70         if(!dep[Ed[i].end]){
 71             dfs1(Ed[i].end , now);
 72             if(md[Ed[i].end] > md[now]){
 73                 md[now] = md[Ed[i].end];
 74                 son[now] = Ed[i].end;
 75                 len[now] = Ed[i].w;
 76             }
 77         }
 78 }
 79 
 80 void dfs2(int now){
 81     if(son[now]){
 82         dp[son[now]] = dp[now] + 1;
 83         cnt[son[now]] = cnt[now] + 1;
 84         dfs2(son[now]);
 85         tag[now] = tag[son[now]] + len[now];
 86         dp[now][0] = -tag[now];
 87     }
 88     cnt[now][0] = 1;
 89     if(ans < dp[now][K] + tag[now]){
 90         ans = dp[now][K] + tag[now];
 91         times = cnt[now][K];
 92     }
 93     else
 94         if(ans == dp[now][K] + tag[now])
 95             times += cnt[now][K];
 96     for(int i = head[now] ; i ; i = Ed[i].upEd)
 97         if(dep[Ed[i].end] == dep[now] + 1 && Ed[i].end != son[now]){
 98             dp[Ed[i].end] = p1;
 99             cnt[Ed[i].end] = p2;
100             p1 += (md[Ed[i].end] - dep[Ed[i].end] + 1) << 1;
101             p2 += (md[Ed[i].end] - dep[Ed[i].end] + 1) << 1;
102             dfs2(Ed[i].end);
103             for(int j = 0 ; j <= md[Ed[i].end] - dep[Ed[i].end] && j <= K - 1 ; ++j)
104                 if(md[now] - dep[now] >= K - 1 - j)
105                     if(ans < tag[Ed[i].end] + dp[Ed[i].end][j] + tag[now] + dp[now][K - 1 - j] + Ed[i].w){
106                         ans = tag[Ed[i].end] + dp[Ed[i].end][j] + tag[now] + dp[now][K - 1 - j] + Ed[i].w;
107                         times = cnt[Ed[i].end][j] * cnt[now][K - 1 - j];
108                     }
109                     else
110                         if(ans == tag[Ed[i].end] + dp[Ed[i].end][j] + tag[now] + dp[now][K - 1 - j] + Ed[i].w)
111                             times += cnt[Ed[i].end][j] * cnt[now][K - 1 - j];
112             for(int j = 1 ; j <= md[Ed[i].end] - dep[Ed[i].end] + 1 && j <= K ; ++j)
113                 if(dp[now][j] < dp[Ed[i].end][j - 1] + tag[Ed[i].end] + Ed[i].w - tag[now]){
114                     dp[now][j] = dp[Ed[i].end][j - 1] + tag[Ed[i].end] + Ed[i].w - tag[now];
115                     cnt[now][j] = cnt[Ed[i].end][j - 1];
116                 }
117                 else
118                     if(dp[now][j] == dp[Ed[i].end][j - 1] + tag[Ed[i].end] + Ed[i].w - tag[now])
119                         cnt[now][j] += cnt[Ed[i].end][j - 1];
120         }
121 }
122 
123 signed main(){
124 #ifndef ONLINE_JUDGE
125     freopen("2993.in" , "r" , stdin);
126     //freopen("2993.out" , "w" , stdout);
127 #endif
128     N = read();
129     M = read();
130     K = read() - 1;
131     for(int i = 1 ; i <= M ; ++i){
132         int a = read() , b = read() , c = read();
133         e[a].push_back(P(b , c));
134         e[b].push_back(P(a , c));
135         ++sz[a];
136         ++sz[b];
137     }
138     for(int i = 1 ; i <= N ; ++i)
139         sort(e[i].begin() , e[i].end());
140     Dijk();
141     create(1);
142     dfs1(1 , 0);
143     dp[1] = p1;
144     p1 += md[1] << 1;
145     cnt[1] = p2;
146     p2 += md[1] << 1;
147     dfs2(1);
148     cout << ans << ' ' << times;
149     return 0;
150 }

转载于:https://www.cnblogs.com/Itst/p/10076779.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值