BZOJ 4016 最短路径树问题 最短路径树构造+点分治

题目:

  BZOJ4016最短路径树问题

 

分析:

  大家都说这是一道强行拼出来的题,属于是两种算法的模板题。

  我们用dijkstra算法算出1为源点的最短路数组,然后遍历一下建出最短路树。

  之后就是裸的点分治算法,一个桶,两个变量就解决了这道题。

代码:

 1 #include<bits/stdc++.h>
 2 #define pi pair<int,int>
 3 #define pq priority_queue
 4 #define mp(a,b) make_pair(a,b)
 5 #define ms(a,x) memset(a,x,sizeof(a))
 6 using namespace std;
 7 const int N=30005;
 8 vector< pi >g[N];
 9 struct node{int y,z,nxt;}e[N*4];
10 int n,m,k,h[N],c=0,dis[N],vis[N],nm[N];
11 int ans2,md,rt,sm,siz[N],s[N],ans,f[N];
12 pq< pi,vector< pi >,greater< pi > >q;
13 void add(int x,int y,int z){
14     e[++c]=(node){y,z,h[x]};h[x]=c;
15     e[++c]=(node){x,z,h[y]};h[y]=c;
16 } void dij(){
17     ms(vis,0);ms(dis,0x3f);
18     dis[1]=0;q.push(mp(0,1));
19     while(!q.empty()){
20         int x=q.top().second;q.pop();
21         if(vis[x]) continue;vis[x]=1;
22         for(int i=0;i<g[x].size();i++){
23             int y=g[x][i].first,
24             d=g[x][i].second;
25             if(dis[y]>dis[x]+d) dis[y]=dis[x]+d,
26             q.push(mp(dis[y],y));
27         }
28     } return ;
29 } void rebuild(int x){
30     vis[x]=1;
31     for(int i=0;i<g[x].size();i++){
32         int y=g[x][i].first,d=g[x][i].second;
33         if(vis[y]||dis[x]+d!=dis[y]) continue;
34         add(x,y,d);rebuild(y);
35     } return ;
36 } void getrt(int x,int fa){
37     siz[x]=1;f[x]=0;
38     for(int i=h[x],y;i;i=e[i].nxt)
39     if(!vis[y=e[i].y]&&y!=fa) getrt(y,x),
40     siz[x]+=siz[y],f[x]=max(f[x],siz[y]);
41     f[x]=max(f[x],sm-siz[x]);
42     if(f[rt]>f[x]) rt=x;return ;
43 } void dfs(int x,int fa,int nw){
44     md=max(md,nw);
45     if(nw==k-1){
46         if(ans==dis[x]) ans2++;
47         if(dis[x]>ans) ans2=1,
48         ans=dis[x];return ;
49     } int nans=-1;
50     if(s[k-1-nw]!=-1) nans=dis[x]+s[k-1-nw];
51     if(ans==nans) ans2+=nm[k-1-nw];
52     if(nans>ans) ans2=nm[k-1-nw],ans=nans;
53     for(int i=h[x],y;i;i=e[i].nxt)
54     if(!vis[y=e[i].y]&&y!=fa) 
55     dis[y]=dis[x]+e[i].z,dfs(y,x,nw+1);
56 } void update(int x,int fa,int nw){
57     if(nw==k-1) return ;
58     if(s[nw]==dis[x]) nm[nw]++;
59     else s[nw]=max(s[nw],dis[x]),nm[nw]=1;
60     for(int i=h[x],y;i;i=e[i].nxt)
61     if(!vis[y=e[i].y]&&y!=fa) update(y,x,nw+1);
62 } void solve(int x){
63     md=0;vis[x]=1;
64     for(int i=h[x],y;i;i=e[i].nxt)
65     if(!vis[y=e[i].y]) dis[y]=e[i].z,
66     dfs(y,x,1),update(y,x,1);
67     for(int i=1;i<=md;i++) s[i]=-1,nm[i]=0;
68     for(int i=h[x],y;i;i=e[i].nxt)
69     if(!vis[y=e[i].y]) sm=siz[y],rt=0,
70     getrt(y,x),solve(rt);
71 } int main(){
72     f[0]=0x3f3f3f3f;scanf("%d%d%d",&n,&m,&k);
73     for(int i=1,x,y,z;i<=m;i++){
74         scanf("%d%d%d",&x,&y,&z);
75         g[x].push_back(mp(y,z));
76         g[y].push_back(mp(x,z));
77     } for(int i=1;i<=n;i++)
78     sort(g[i].begin(),g[i].end());
79     dij();ms(vis,0);rebuild(1);
80     sm=n;rt=0;ms(vis,0);
81     ms(dis,0);ms(s,-1);
82     getrt(1,0);solve(rt);
83     printf("%d %d\n",ans,ans2);
84     return 0;
85 }
最短路树+点分治

 

posted @ 2019-02-27 20:07  杜宇一声  阅读(302)  评论(0编辑  收藏  举报