[CF1051F] The Shortest Statement

CF 题目传送门

洛谷 题目传送门

一道最短路的题。

首先题目条件给出m-n<=20,可以看出这个图近乎一棵树。

首先跑出图的dfs树,预处理出树上距离等信息。

再枚举非树边,对每一个非树边的端点跑一边dijkstra。

可以看出最多有42个这样的点。

回答询问的时候,用树上距离作为答案,再用每一个非树边的端点更新答案即可。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 #define ll long long
  6 #define bro(i) ((i%2)?(i+1):(i-1))
  7 #define MAXN 100005
  8 using namespace std;
  9 
 10 int n,m,q;
 11 int hd[MAXN],to[MAXN<<1],nx[MAXN<<1],fr[MAXN<<1],ec;
 12 bool used[MAXN<<1];
 13 ll len[MAXN<<1];
 14 
 15 void edge(int af,int at,ll el)
 16 {
 17     to[++ec]=at;
 18     fr[ec]=af;
 19     nx[ec]=hd[af];
 20     len[ec]=el;
 21     hd[af]=ec;
 22 }
 23 
 24 int f[MAXN][20],dep[MAXN];
 25 
 26 namespace treedata
 27 {
 28     ll dis[MAXN];
 29 }
 30 
 31 namespace graphdata
 32 {
 33     ll dis[50][MAXN];
 34 }
 35 
 36 void dfs(int p,int fa,ll dl)
 37 {
 38     using namespace treedata;
 39     f[p][0]=fa;
 40     dep[p]=dep[fa]+1;
 41     dis[p]=dis[fa]+dl;
 42     for(int i=hd[p];i;i=nx[i])
 43         if(!dep[to[i]])
 44             dfs(to[i],p,len[i]),used[i]=used[bro(i)]=1;
 45 }
 46 
 47 void pre()
 48 {
 49     for(int i=1;i<=18;i++)
 50         for(int j=1;j<=n;j++)
 51             f[j][i]=f[f[j][i-1]][i-1];
 52 }
 53 
 54 int lca(int x,int y)
 55 {
 56     if(dep[x]<dep[y])swap(x,y);
 57     for(int i=18;i>=0;i--)
 58         if(dep[f[x][i]]>=dep[y])x=f[x][i];
 59     if(x==y)return x;
 60     for(int i=18;i>=0;i--)
 61         if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
 62     return f[x][0];
 63 }
 64 
 65 bool mark[MAXN];
 66 int id[MAXN],mc;
 67 bool v[MAXN];
 68 
 69 struct data
 70 {
 71     int p;
 72     ll d;
 73     friend bool operator < (data q,data w)
 74     {
 75         return q.d>w.d;
 76     }
 77 };
 78 
 79 priority_queue<data>qq;
 80 
 81 void dijkstra(int s)
 82 {
 83     while(!qq.empty())qq.pop();
 84     using namespace graphdata;
 85     memset(v,0,sizeof(v));
 86     memset(dis[id[s]],0x3f,sizeof(dis[id[s]]));
 87     dis[id[s]][s]=0;
 88     qq.push((data){s,0});
 89     while(!qq.empty())
 90     {
 91         data nw=qq.top();
 92         qq.pop();
 93         if(v[nw.p])continue;
 94         v[nw.p]=1;
 95         for(int i=hd[nw.p];i;i=nx[i])
 96         {
 97             if((!v[to[i]])&&dis[id[s]][to[i]]>nw.d+len[i])
 98             {
 99                 dis[id[s]][to[i]]=nw.d+len[i];
100                 qq.push((data){to[i],dis[id[s]][to[i]]});
101             }
102         }
103     }
104 }
105 
106 ll treedis(int x,int y)
107 {
108     using namespace treedata;
109     int l=lca(x,y);
110     return dis[x]+dis[y]-(dis[l]<<1);
111 }
112 
113 ll graphdis(int x,int y,int sid)
114 {
115     using namespace graphdata;
116     return dis[sid][x]+dis[sid][y];
117 }
118 
119 int main()
120 {
121     scanf("%d%d",&n,&m);
122     for(int i=1;i<=m;i++)
123     {
124         int a,b;ll c;
125         scanf("%d%d%I64d",&a,&b,&c);
126         edge(a,b,c);
127         edge(b,a,c);
128     }
129     dfs(1,1,0);
130     pre();
131     for(int i=1;i<=ec;i+=2)
132         if(!used[i])
133             mark[fr[i]]=mark[to[i]]=1;
134     for(int i=1;i<=n;i++)
135     {
136         if(!mark[i])continue;
137         id[i]=++mc;
138         dijkstra(i);
139     }
140     scanf("%d",&q);
141     for(int i=1;i<=q;i++)
142     {
143         int x,y;
144         scanf("%d%d",&x,&y);
145         ll ans=treedis(x,y);
146         for(int j=1;j<=mc;j++)
147             ans=min(ans,graphdis(x,y,j));
148         printf("%I64d\n",ans);
149     }
150     return 0;
151 }

猜你喜欢

转载自www.cnblogs.com/eternhope/p/9826949.html