[bzoj 4016] [Fjoi 2014] 最短路径树问题

来源:互联网 发布:大学生创业成功率数据 编辑:程序博客网 时间:2024/06/08 06:27

题目在这里

有生之年参加的第一次省选,当时太年轻太弱又碰到3道丧病题果断爆零了。(虽然现在还是很弱)考场上以为这是一道树形dp,因为树上的题目除了dfs和dp外啥都不知道。。。。。

这题是点分治大裸题(我也只会写大裸题),然而我建树写了两节课。。。大致就是先从1号点跑一遍spfa或heap-dijkstra,显然满足dis[x]+w[x][y]==dis[y]的边在最短路径上。由于要求路径字典序最小,就优先走编号小的节点,这样一个点第一次被dfs到就一定是1到它的路径字典序最小了。

建完树之后直接点分治。记一下每棵子树的到重心刚好经过x个节点的路径的最大值_max[x],在记录一下这个最大值出现多少次,然后无脑码个150行注意一下就A了。

//最短路树+点分治 记录方案数 #include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <deque>#include <map>#include <set>#include <ctime>using namespace std;const int MAXN=30005,MAXM=60005,INF=1000000005;struct Edge{     int pre,from,to,cost,pos; bool flag;}E[MAXM*2],tmp[MAXM*2];int n,m,K,tot,fst[MAXN],dis[MAXN],depth[MAXN],size[MAXN],maxsize[MAXN],w[MAXN],_max[MAXN],nowmax[MAXN],st,ed,nowroot,cnt,amo[MAXN],nowamo[MAXN],son[MAXN],ans,sum;bool vis[MAXN]; struct Node{     int x,val;    Node () {} Node(int _x,int _val) { x=_x,val=_val; }  }; priority_queue<Node> H; bool operator < (Node a,Node b) { return a.val>b.val; }bool cmp1(const Edge &a,const Edge &b) { return (a.from<b.from) || (a.from==b.from && a.to<b.to); }bool cmp2(const Edge &a,const Edge &b) { return a.pos<b.pos; }int Get(){     char ch; int v=0; bool f=false;    while (!isdigit(ch=getchar())) if (ch=='-') f=true; v=ch-48;    while (isdigit(ch=getchar())) v=v*10+ch-48;    if (f) return -v;else return v;   }void add(int x,int y,int c,bool f){     E[++tot].pre=fst[x],fst[x]=tot,E[tot].from=x,E[tot].to=y,E[tot].cost=c,E[tot].flag=false;    if (f) E[++tot].pre=fst[y],fst[y]=tot,E[tot].from=y,E[tot].to=x,E[tot].cost=c,E[tot].flag=false;}void Dijkstra() {     for (int i=1;i<=n;i++) dis[i]=INF,vis[i]=false; dis[1]=0,H.push(Node(1,dis[1])),vis[1]=true;    while (!H.empty())      {          Node tmp=H.top(); H.pop();         int x=tmp.x; if (tmp.val!=dis[x]) continue; vis[x]=true;         for (int i=fst[x];i;i=E[i].pre)          {             int y=E[i].to;            if (!vis[y] && dis[x]+E[i].cost<dis[y]) dis[y]=dis[x]+E[i].cost,H.push(Node(y,dis[y]));          }      }}void dfs_init(int x) //建树 {     vis[x]=true;     for (int i=fst[x];i;i=E[i].pre)      {         int y=E[i].to;         if (!vis[y] && dis[x]+E[i].cost==dis[y]) depth[y]=depth[x]+1,E[i].flag=true,dfs_init(y);       }}void Build_Tree(){     for (int i=1;i<=tot;i++) tmp[i].from=E[i].from,tmp[i].to=E[i].to,tmp[i].cost=E[i].cost,tmp[i].pos=i;    sort(tmp+1,tmp+1+tot,cmp1); for (int i=1;i<=n;i++) vis[i]=false,fst[i]=0; int ttot=tot; tot=0;     for (int i=ttot;i>=1;i--) add(tmp[i].from,tmp[i].to,tmp[i].cost,0);     depth[1]=1; dfs_init(1);     for (int i=1;i<=tot;i++) tmp[i].from=E[i].from,tmp[i].to=E[i].to,tmp[i].cost=E[i].cost,tmp[i].flag=E[i].flag;    for (int i=1;i<=n;i++) fst[i]=0,vis[i]=false; ttot=tot; tot=0;     for (int i=1;i<=ttot;i++) if (tmp[i].flag) add(tmp[i].from,tmp[i].to,tmp[i].cost,1); maxsize[0]=MAXN; } void dfs_size(int x,int fa) //算出孩子数 {      maxsize[x]=0,size[x]=1,cnt++;     for (int i=fst[x];i;i=E[i].pre)      {         int y=E[i].to;        if (y!=fa && !vis[y]) dfs_size(y,x),size[x]+=size[y],maxsize[x]=max(maxsize[x],size[y]);       }}void dfs_root(int x,int fa) //找重心 {      maxsize[x]=max(maxsize[x],cnt-size[x]);     if (maxsize[x]<maxsize[nowroot]) nowroot=x;     for (int i=fst[x];i;i=E[i].pre)      {         int y=E[i].to;        if (y!=fa && !vis[y]) dfs_root(y,x);       }}void modify(int &a,int b,int &c,int v) { if (b>a) a=b,c=v;else if (a==b) c+=v; }void dfs_work(int x,int fa) //暴力统计 {     if (depth[x]>K) return;     son[++tot]=x; int tmp=_max[K-depth[x]]+w[x];       modify(nowmax[depth[x]],w[x],nowamo[depth[x]],1); modify(ans,tmp,sum,amo[K-depth[x]]);     for (int i=fst[x];i;i=E[i].pre)      {         int y=E[i].to;         if (y!=fa && !vis[y]) w[y]=w[x]+E[i].cost,depth[y]=depth[x]+1,dfs_work(y,x);       }} void work(int root) //计算路径经过x的答案 {     vis[root]=true; w[root]=0,depth[root]=0; tot=0;     for (int i=fst[root];i;i=E[i].pre)       {         int y=E[i].to;        if (!vis[y])           {            st=tot+1,depth[y]=1,w[y]=E[i].cost,dfs_work(y,-1),ed=tot;             for (int j=st;j<=ed;j++)               modify(_max[depth[son[j]]],nowmax[depth[son[j]]],amo[depth[son[j]]],nowamo[depth[son[j]]]),              nowmax[depth[son[j]]]=0,nowamo[depth[son[j]]]=0;           }       }     for (int i=1;i<=tot;i++)       {         if (depth[son[i]]==K) modify(ans,w[son[i]],sum,1);        nowmax[depth[son[i]]]=_max[depth[son[i]]]=amo[depth[son[i]]]=nowamo[depth[son[i]]]=0;      }}void dfs(int x,int fa) //最外层dfs {      cnt=nowroot=0; int root=0; dfs_size(x,fa);    dfs_root(x,fa); root=nowroot;      work(root);      for (int i=fst[root];i;i=E[i].pre)      {          int y=E[i].to;         if (!vis[y]) dfs(y,root);        }}int main(){     freopen("mindistree.in","r",stdin);    freopen("mindistree.out","w",stdout);    n=Get(),m=Get(),K=Get(); K--; int u,v,d; tot=0;     for (int i=1;i<=m;i++) u=Get(),v=Get(),d=Get(),add(u,v,d,1);    Dijkstra();     Build_Tree();    ans=sum=0;      dfs(1,-1);     printf("%d %d\n",ans,sum);    return 0;} 
0 0
原创粉丝点击