您的位置:首页 > 其它

Wannafly挑战赛2 B 题 Travel 【最短路 + 思维】

2017-10-31 10:36 495 查看
传送门

//题意: 在一个环上, 有许多城市, 告诉相邻城市之间距离. 然后在这些城市中有一些传送门, 连接两座城市和一个距离, 然后给出q次询问, 问两座城市之间的最小距离.

//思路: 本题的关键点在于传送门的数量很少, 只有20座, 然后观察可发现, 一个城市到另一个城市的最短距离要么就是走环上的距离, 要么就是起点通过某一个有传送门的点再到达终点, 所以我们先预处理出所有特殊点到所有点的最短距离, 特殊点不多只有40个, 复杂度是40*n*logn, 然后q询问, 直接暴力枚举40个点和O1的环上距离,即可出答案. 总复杂为(40*n*logn + q*40).

AC Code

const ll INF = 1e18;
const int maxn = 1e5+5;
int cas=1;
struct node
{
int to; ll w; int next;
bool operator < (const node& a) const {
return a.w < w;
}
}e[maxn<<1];
int cnt,head[maxn];
void add(int u,int v,ll w)
{
e[cnt ] = (node){v,w,head[u]};
head[u] = cnt++;
}
bool vis[maxn]; ll dis[50][maxn];
int id[50]; int n,m;
void dij(int st)
{
for(int i=1;i<=n;i++) dis[st][i] = INF;
priority_queue<node>q; Fill(vis,0);
dis[st][id[st]] = 0; q.push((node){id[st],0,0});
while(!q.empty()){
node u = q.top();
q.pop();
if(vis[u.to]) continue;
vis[u.to] = 1;

for(int i=head[u.to]; ~i ; i=e[i].next){
node k = e[i];
if(dis[st][k.to] > dis[st][u.to] + k.w){
dis[st][k.to] = dis[st][u.to] + k.w;
q.push((node){k.to,dis[st][k.to],0});
}
}
}
}
ll sum[maxn],d[maxn];
vector<int>ve; ll tot;
void solve()
{
while(~scanf("%d%d",&n,&m)){
Fill(head,-1); Fill(sum,0);
cnt = 0; tot = 0;
for(int i=2;i<=n+1;i++) {
scanf("%lld",&d[i]);
tot += d[i];
if(i==n+1) {
add(1,n,d[i]);
add(n,1,d[i]);
}
else{
add(i,i-1,d[i]);
add(i-1,i,d[i]);
}
sum[i] = sum[i-1] + d[i];
}
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w);
ve.push_back(u); ve.push_back(v);
}
sort(ve.begin(),ve.end());
ve.erase(unique(ve.begin(),ve.end()),ve.end());
int tt = 0;
for(int i=0;i<ve.size();i++){
id[++tt] = ve[i];
dij(tt);
}
int q; scanf("%d",&q);
while(q--){
int u,v;
scanf("%d%d",&u,&v);
ll ans = min(abs(sum[v] - sum[u]),tot - abs(sum[v] - sum[u]));
for(int i=1;i<=tt;i++){
ans = min(ans,dis[i][u] + dis[i][v]);
}
cout << ans << endl;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: