商务旅行

来源:互联网 发布:起点中文网数据 编辑:程序博客网 时间:2024/06/14 00:17

传送门
SPFA超时妥妥的!
N-1条边,树上找最短路,八成是LCA
用经过的点两两建立要查询的LCA,边权设为1.
就可以转化为小机房的树那个题目233

#include <cstdio>#include <iostream>using namespace std;const int maxm=501000;struct node{    int net;    int to;    int cost;    int lca;    int ans;};bool vis[maxm];int fat[maxm];node edge[2][2*maxm];int cnt[2],head[2][maxm];int dis[maxm]; int t;void add(int id,int x,int y,int c){    edge[id][++cnt[id]].to=y;    edge[id][cnt[id]].cost=c;    edge[id][cnt[id]].net=head[id][x];    head[id][x]=cnt[id];}int find(int x){    if(fat[x]==x) return x;    else return fat[x]=find(fat[x]);}void dfs(int x,int f,int sum){    dis[x]+=dis[f]+sum;    vis[x]=1;    fat[x]=x;    for(int K=head[0][x];K;K=edge[0][K].net)    {        int p=edge[0][K].to;        if(vis[p]) continue;        dfs(p,x,edge[0][K].cost);        fat[p]=x;    }    for(int i=head[1][x];i;i=edge[1][i].net)    {        int p=edge[1][i].to;        if(!vis[p]||edge[1][i].lca) continue;        edge[1][i].lca=find(p);         int ans=dis[x]+dis[p]-2*dis[edge[1][i].lca];        //printf("%d %d %d %d\n",x,p,edge[1][i].lca,ans);        edge[1][i].ans=ans;        t+=ans;        if(i%2)         edge[1][i+1].lca=edge[1][i].lca,edge[1][i+1].ans=ans;        else         edge[1][i-1].lca=edge[1][i].lca,edge[1][i-1].ans=ans;    }}int main(){    int n,m;    scanf("%d",&n);    for(int i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        add(0,x,y,1);        add(0,y,x,1);    }    scanf("%d",&m);    int last=1;    //scanf("%d",&last);    for(int i=1;i<=m;i++)    {        int x;        scanf("%d",&x);        add(1,last,x,0),add(1,x,last,0);        last=x;    }    dfs(1,0,0);    printf("%d",t);}
原创粉丝点击