V.[FJOI2014]最短路径树问题
这题已经在我的收藏夹里吃了大半年的灰了……主要是因为他们有人把这题归到了树形DP里面,然后我就傻乎乎地把它收藏了……
首先,假设我们已经求出了这个“最短路径树”,剩下的就是点分治的板子了。
而这个“最短路径树”,首先可以通过Dijkstra跑出最短路径DAG,然后在DAG上用bfs即可求出字典序最小的树。
总的来说似乎是把两道板子强行缝在了一起?老缝合怪了
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,p;
namespace cd{
int head[30100],cnt,buc[30100],bc[30100],sz[30100],msz[30100],ROOT,SZ,mx,ct;
struct node{
int to,next,val;
}edge[60010];
void ae(int u,int v,int w){
edge[cnt].next=head[u],edge[cnt].to=v,edge[cnt].val=w,head[u]=cnt++;
edge[cnt].next=head[v],edge[cnt].to=u,edge[cnt].val=w,head[v]=cnt++;
}
bool vis[30100];
void getsz(int x,int fa){
sz[x]=1;
for(int i=head[x];i!=-1;i=edge[i].next)if(edge[i].to!=fa&&!vis[edge[i].to])getsz(edge[i].to,x),sz[x]+=sz[edge[i].to];
}
void getroot(int x,int fa){
sz[x]=1,msz[x]=0;
for(int i=head[x];i!=-1;i=edge[i].next)if(edge[i].to!=fa&&!vis[edge[i].to])getroot(edge[i].to,x),sz[x]+=sz[edge[i].to],msz[x]=max(msz[x],sz[edge[i].to]);
msz[x]=max(msz[x],SZ-sz[x]);
if(msz[x]<msz[ROOT])ROOT=x;
}
void get1(int x,int fa,int DEP,int DIS){
if(DEP>p)return;
if(mx<DIS+buc[p-DEP]&&bc[p-DEP])mx=DIS+buc[p-DEP],ct=0;
if(mx==DIS+buc[p-DEP])ct+=bc[p-DEP];
for(int i=head[x];i!=-1;i=edge[i].next)if(edge[i].to!=fa&&!vis[edge[i].to])get1(edge[i].to,x,DEP+1,DIS+edge[i].val);
}
void get2(int x,int fa,int DEP,int DIS){
if(DEP>p)return;
if(buc[DEP]<DIS)buc[DEP]=DIS,bc[DEP]=0;
if(buc[DEP]==DIS)bc[DEP]++;
for(int i=head[x];i!=-1;i=edge[i].next)if(edge[i].to!=fa&&!vis[edge[i].to])get2(edge[i].to,x,DEP+1,DIS+edge[i].val);
}
void work(int x){
buc[0]=0,bc[0]=1;
for(int i=head[x];i!=-1;i=edge[i].next)if(!vis[edge[i].to])get1(edge[i].to,x,1,edge[i].val),get2(edge[i].to,x,1,edge[i].val);
for(int i=1;i<=p&&buc[i];i++)buc[i]=bc[i]=0;
}
void solve(int x){
work(x),getsz(x,0),vis[x]=true;
for(int i=head[x],y;i!=-1;i=edge[i].next){
if(vis[y=edge[i].to])continue;
ROOT=0,SZ=sz[y],getroot(y,x),solve(ROOT);
}
}
void calc(){
msz[0]=n+1,SZ=n,getroot(1,0),solve(ROOT);
}
}
namespace Gra{
int head[30100],cnt,dis[30100];
struct node{
int to,next,val;
}edge[120010];
void ae(int u,int v,int w){
edge[cnt].next=head[u],edge[cnt].to=v,edge[cnt].val=w,head[u]=cnt++;
edge[cnt].next=head[v],edge[cnt].to=u,edge[cnt].val=w,head[v]=cnt++;
}
bool vis[30100];
void Dijkstra(){
priority_queue<pair<int,int> >q;
memset(dis,0x3f3f3f3f,sizeof(dis)),dis[1]=0,q.push(make_pair(0,1));
while(!q.empty()){
int x=q.top().second;q.pop();
if(vis[x])continue;vis[x]=true;
for(int i=head[x],y;i!=-1;i=edge[i].next)if(dis[y=edge[i].to]>dis[x]+edge[i].val)dis[y]=dis[x]+edge[i].val,q.push(make_pair(-dis[y],y));
}
// for(int i=1;i<=n;i++)printf("%d ",dis[i]);puts("");
}
void Build(){
queue<int>q;q.push(1),memset(vis,false,sizeof(vis)),vis[1]=true;
while(!q.empty()){
int x=q.front();q.pop();
vector<pair<int,int> >v;
for(int i=head[x];i!=-1;i=edge[i].next)if(dis[edge[i].to]==dis[x]+edge[i].val)v.push_back(make_pair(edge[i].to,edge[i].val));
sort(v.begin(),v.end());
for(auto i:v)if(!vis[i.first])vis[i.first]=true,q.push(i.first),cd::ae(x,i.first,i.second);
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&p),p--,memset(Gra::head,-1,sizeof(Gra::head)),memset(cd::head,-1,sizeof(cd::head));
for(int i=1,x,y,z;i<=m;i++)scanf("%d%d%d",&x,&y,&z),Gra::ae(x,y,z);
Gra::Dijkstra(),Gra::Build();
cd::calc();
printf("%d %d\n",cd::mx,cd::ct);
return 0;
}