HYSBZ - 4016 最短路径树问题 点分治 + 最短路径最小字典序

题目传送门

题解:首先对于给定的图,需要找到那些从1好点出发然后到x号点的最短路, 如果有多条最短路就要找到字典序最小的路,这样扣完这些边之后就会有一棵树。然后再就是很普通的点分治了。

对于扣边这个问题, 我们先跑一遍最短路,这样就可以得到1号点到其他的点的距离。

然后在跑一遍dfs, 我们在跑dfs找路的时候, 可以通过 d[u] + ct[i] == d[v] 来判断是不是最短路是否可以走这条边, 然后我们再从所有可能边中的最小编号出发,这样我们就能保证字典序最小了。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
  4 #define LL long long
  5 #define ULL unsigned LL
  6 #define fi first
  7 #define se second
  8 #define pb push_back
  9 #define lson l,m,rt<<1
 10 #define rson m+1,r,rt<<1|1
 11 #define lch(x) tr[x].son[0]
 12 #define rch(x) tr[x].son[1]
 13 #define max3(a,b,c) max(a,max(b,c))
 14 #define min3(a,b,c) min(a,min(b,c))
 15 typedef pair<int,int> pll;
 16 const int inf = 0x3f3f3f3f;
 17 const LL INF = 0x3f3f3f3f3f3f3f3f;
 18 const LL mod =  (int)1e9+7;
 19 const int N = 3e4 + 100;
 20 vector<pll> vc[N];
 21 int d[N];
 22 void dij(){
 23     memset(d, inf, sizeof(d));
 24     priority_queue<pll, vector<pll>, greater<pll> > q;
 25     d[1] = 0;
 26     q.push(pll(0,1));
 27     int x, dd, v, ct;
 28     while(!q.empty()){
 29         x = q.top().se, dd = q.top().fi;
 30         q.pop();
 31         if(dd != d[x]) continue;
 32         for(int i = 0; i < vc[x].size(); ++i){
 33             v = vc[x][i].fi , ct = vc[x][i].se;
 34             if(d[v] > d[x] + ct){
 35                 d[v] = d[x] + ct;
 36                 q.push(pll(d[v], v));
 37             }
 38         }
 39     }
 40     return;
 41 }
 42 int vis[N];
 43 int head[N], to[N<<2], val[N<<2], nt[N<<2], tot = 0;
 44 void add(int u, int v, int ct){
 45     to[tot] = v;
 46     val[tot] = ct;
 47     nt[tot] = head[u];
 48     head[u] = tot++;
 49     return ;
 50 }
 51 void dfs(int u){
 52     vis[u] = 1;
 53     int v, dd;
 54     for(int i = 0; i < vc[u].size(); i++){
 55         v = vc[u][i].fi, dd = vc[u][i].se;
 56         if(vis[v] || d[v] != d[u] + dd) continue;
 57         add(u, v, dd);
 58         add(v, u, dd);
 59         dfs(v);
 60     }
 61     return ;
 62 }
 63 int sz[N];
 64 int rt, minval;
 65 int n, m, k;
 66 void get_rt(int o, int u, int num){
 67     sz[u] = 1;
 68     int v;
 69     int maxval = 0;
 70     for(int i = head[u]; ~i; i = nt[i]){
 71         v = to[i];
 72         if(v == o || vis[v]) continue;
 73         get_rt(u, v, num);
 74         sz[u] += sz[v];
 75         maxval = max(maxval, sz[v]);
 76     }
 77     if(o) maxval = max(maxval, num - sz[u]);
 78     if(maxval < minval){
 79         minval = maxval;
 80         rt = u;
 81     }
 82 }
 83 int fans = 0, fcnt = 0;
 84 int cnt[N], dis[N];
 85 void Update(int vval, int num){
 86     if(fans == vval) fcnt += num;
 87     else if(fans < vval) fans = vval, fcnt = num;
 88     return ;
 89 }
 90 void Dfs(int o, int u, int w, int num){
 91     sz[u] = 1;
 92     if(num == k-1)
 93         Update(w, 1);
 94     if(k >= num && dis[k-num]){
 95         Update(w+dis[k-num], cnt[k-num]);
 96     }
 97     for(int i = head[u]; ~i; i = nt[i]){
 98         int v = to[i];
 99         if(v == o || vis[v]) continue;
100         Dfs(u, v,w+val[i], num+1);
101         sz[u] += sz[v];
102     }
103     return ;
104 }
105 void Change(int o, int u, int w, int num, int op){
106     if(num >= k) return ;
107     if(op == 1) {
108         if(dis[num+1] < w) dis[num+1] = w, cnt[num+1] = 1;
109         else if(dis[num+1] == w) cnt[num+1]++;
110     }
111     else dis[num+1] = cnt[num+1] = 0;
112     for(int i = head[u]; ~i; i = nt[i]){
113         int v = to[i];
114         if(v == o || vis[v]) continue;
115         Change(u, v, w+val[i], num+1, op);
116     }
117     return ;
118 }
119 void solve(int x, int num){
120     if(num <= 1) return ;
121     minval = inf;
122     get_rt(0, x, num);
123     vis[rt] = 1;
124     int v;
125     for(int i = head[rt]; ~i; i = nt[i]){
126         v = to[i];
127         if(vis[v]) continue;
128         Dfs(0, v, val[i], 1);
129         Change(0, v, val[i], 1, 1);
130     }
131     for(int i = head[rt]; ~i; i = nt[i]){
132         v = to[i];
133         if(vis[v]) continue;
134         Change(0, v, val[i], 1, 0);
135     }
136     for(int i = head[rt]; ~i; i = nt[i]){
137         v = to[i];
138         if(vis[v]) continue;
139         solve(v, sz[v]);
140     }
141     return ;
142 }
143 int main(){
144     int u, v, w;
145     memset(head, -1, sizeof(head));
146     scanf("%d%d%d", &n, &m, &k);
147     for(int i = 1; i <= m; i++){
148         scanf("%d%d%d", &u, &v, &w);
149         vc[u].pb(pll(v,w));
150         vc[v].pb(pll(u,w));
151     }
152     dij();
153     dfs(1);
154     memset(vis, 0, sizeof(vis));
155     solve(1, n);
156     printf("%d %d", fans, fcnt);
157     return 0;
158 }
View Code

 

posted @ 2018-11-01 17:36  Schenker  阅读(387)  评论(0编辑  收藏  举报