BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
Description
给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。
Input
第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
Output
输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
Sample Input
6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1
Sample Output
3 4
首先要理解题中‘字典序最小的含义’。
跑一边dij,对每个点开vector,如果更新前dis[to]==dis[x]+val[i]说明这条反边在最短路图上,就把这条反边加入to的vector中。
于是我们就有了一个最短路图,对每个vector进行排序,然后求出整个图的dfs树就是题中所求的最短路树。
然后就是一个点分治可做的问题了。
维护出当前深度下最长路径和最长路径的条数即可。
代码:
#include <stdio.h> #include <string.h> #include <algorithm> #include <stdlib.h> #include <vector> #include <ext/pb_ds/priority_queue.hpp> using namespace std; using namespace __gnu_pbds; #define N 30050 #define M 60050 #define RR register inline char nc() { static char buf[100000],*p1,*p2; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int rd() { register int x=0; register char s=nc(); while(s<'0'||s>'9') s=nc(); while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc(); return x; } int n,m,vis[N],dis[N],dfn[N],K; __gnu_pbds::priority_queue<pair<int,int> >q; vector<int>v[N]; int head[N],to[M<<1],nxt[M<<1],val[M<<1],cnt=1; __attribute__((optimize("-O2")))void add(int u,int v,int w) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; } __attribute__((optimize("-O2")))void dij() { memset(dis,0x3f,sizeof(dis)); dis[1]=0; q.push(make_pair(0,1)); while(!q.empty()) { RR int x=q.top().second,i; q.pop(); if(vis[x]) continue; vis[x]=1; for(i=head[x];i;i=nxt[i]) { if(dis[to[i]]+val[i]==dis[x]) { // puts("FUCK"); v[to[i]].push_back(i^1); } } for(i=head[x];i;i=nxt[i]) { if(dis[to[i]]>dis[x]+val[i]) { dis[to[i]]=dis[x]+val[i]; q.push(make_pair(-dis[to[i]],to[i])); } } } } __attribute__((optimize("-O2")))inline bool cmp(int x,int y) {return to[x]<to[y];} struct Fenzhi { int head[N],to[M<<1],nxt[M<<1],val[M<<1],cnt,used[N],sum,ans,tot; int f[N],siz[N],root,d[N],dep[N],maxdep,maxmaxdep; int g[N],h[N],t1[N],t2[N];//g[i]表示深度为i的点到根路径的最大值,h[i]为对应的方案数。 __attribute__((optimize("-O2")))void add(int u,int v,int w) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; } __attribute__((optimize("-O2")))void get_root(int x,int y) { RR int i; siz[x]=1; f[x]=0; for(i=head[x];i;i=nxt[i]) { if(to[i]!=y&&!used[to[i]]) { get_root(to[i],x); siz[x]+=siz[to[i]]; f[x]=max(f[x],siz[to[i]]); } } f[x]=max(f[x],sum-siz[x]); if(f[x]<f[root]) root=x; } __attribute__((optimize("-O2")))void get_dep(int x,int y) { maxdep=max(maxdep,dep[x]); siz[x]=1; RR int i; for(i=head[x];i;i=nxt[i]) { if(to[i]!=y&&!used[to[i]]) { d[to[i]]=d[x]+val[i]; dep[to[i]]=dep[x]+1; if(t1[dep[to[i]]]<d[to[i]]) { t1[dep[to[i]]]=d[to[i]]; t2[dep[to[i]]]=1; }else if(t1[dep[to[i]]]==d[to[i]]) { t2[dep[to[i]]]++; } get_dep(to[i],x); siz[x]+=siz[to[i]]; } } } __attribute__((optimize("-O2")))void work(int x) { maxmaxdep=0; used[x]=1; RR int i,j; for(i=head[x];i;i=nxt[i]) { if(!used[to[i]]) { maxdep=1; d[to[i]]=val[i]; dep[to[i]]=1; t1[1]=val[i]; t2[1]=1; get_dep(to[i],x); for(j=1;j<=maxdep&&j<=K;j++) { if(ans<t1[j]+g[K-j]) ans=t1[j]+g[K-j],tot=t2[j]*h[K-j]; else if(ans==t1[j]+g[K-j]) tot+=t2[j]*h[K-j]; } for(j=1;j<=maxdep&&j<=K;j++) { if(t1[j]>g[j]) g[j]=t1[j],h[j]=t2[j]; else if(t1[j]==g[j]) h[j]+=t2[j]; } for(j=1;j<=maxdep;j++) t1[j]=-1<<30,t2[j]=0; maxmaxdep=max(maxmaxdep,maxdep); } } for(i=1;i<=maxmaxdep&&i<=K;i++) g[i]=-1<<30,h[i]=0; for(i=head[x];i;i=nxt[i]) { if(!used[to[i]]) { root=0; sum=siz[to[i]]; get_root(to[i],x); work(root); } } } __attribute__((optimize("-O2")))void solve() { sum=n; root=0; f[0]=1<<30; get_root(1,0); work(root); printf("%d %d\n",ans,tot); } }F; __attribute__((optimize("-O2")))void dfs(int x) { RR int i; dfn[x]=1; sort(v[x].begin(),v[x].end(),cmp); for(i=0;i<(int)v[x].size();i++) { int t=v[x][i],c=val[t],v=to[t]; if(!dfn[v]) { dfn[v]=1; F.add(x,v,c); F.add(v,x,c); dfs(v); } } } __attribute__((optimize("-O2")))int main() { n=rd(); m=rd(); K=rd(); K--; RR int i,x,y,z; for(i=1;i<=m;i++) { x=rd(); y=rd(); z=rd(); add(x,y,z); add(y,x,z); } dij(); dfs(1); F.h[0]=1; F.solve(); }