题解参考:点击打开链接
首先如果Taku使用了第二种魔法,那么有K步的移动是可以确定的,于是我们记录每条边走完后, 通过第一种魔法下一步是哪条边,这样可以倍增算出K步后在哪儿,于是可以直接建图,求最短路即可。
重要的话一定要加粗说!**答案会爆int,另外题意有毒!**
倍增的是边:
#include <bits/stdc++.h>
using namespace std;
typedef pair<long long,int> pli;
const int maxm=200005;
const long long inf=0x3f3f3f3f3f3f3f3f;
int T,n,m,K,u[maxm],v[maxm],w[maxm],nxt[maxm],dp[maxm][20],magic[maxm];
long long d[maxm],cost[maxm][20],co[maxm];
priority_queue<pli,vector<pli>,greater<pli> > que;
struct node {
int v,id,w;
node(){}
node(int v,int id,int w):v(v),id(id),w(w){}
bool operator<(const node &rhs)const{
if (w!=rhs.w)
return w<rhs.w;
return v<rhs.v;
}
};
vector<node> G[maxm];
inline int getid(int u,int v,int w,int id=0,bool debug=false) {
if (u==n)
return m;
int x=lower_bound(G[u].begin(),G[u].end(),node(0,v,w))-G[u].begin();
if (v!=G[u][x].v)
return G[u][x].id;
if ((int)G[u].size()==1)
return G[u][x].id;
else {
if (x>0&&x+1==(int)G[u].size())
return G[u][x-1].id;
if (x==0)
return G[u][x+1].id;
else {
node t=G[u][x-1],s=G[u][x+1];
t.w=abs(G[u][x].w-G[u][x-1].w);
s.w=abs(G[u][x].w-G[u][x+1].w);
if (debug) {
printf("%d %d %d %d\n",t.id,t.w,s.id,s.w);
}
if (t<s)
return t.id;
else
return s.id;
}
}
}
int main()
{
//freopen("out.txt","w",stdout);
scanf("%d",&T);
for (int cas=1;cas<=T;++cas) {
scanf("%d%d%d",&n,&m,&K);
for (int i=1;i<=n;++i)
G[i].clear();
m<<=1;
for (int i=0;i<m;i+=2) {
scanf("%d%d%d",&u[i],&v[i],&w[i]);
w[i+1]=w[i];
u[i+1]=v[i];
v[i+1]=u[i];
G[u[i]].push_back(node(v[i],i,w[i]));
G[v[i]].push_back(node(u[i],i+1,w[i]));
}
u[m]=v[m]=n;
if (n==1) {
printf("Case #%d: 0\n",cas);
continue;
}
for (int i=1;i<=n;++i)
sort(G[i].begin(),G[i].end());
for (int i=0;i<m;++i) {
nxt[i]=getid(v[i],u[i],w[i],i);
dp[i][0]=nxt[i];
cost[i][0]=(nxt[i]!=m);
}
cost[m][0]=0;
dp[m][0]=m;
magic[m]=nxt[m]=m;
for (int i=1;i<20;++i) {
dp[m][i]=m;
cost[m][i]=0;
for (int j=0;j<m;++j) {
dp[j][i]=dp[dp[j][i-1]][i-1];
cost[j][i]=cost[j][i-1]+cost[dp[j][i-1]][i-1];
}
}
for (int i=0;i<m;++i) {
magic[i]=i;
co[i]=0;
for (int j=0;j<20;++j)
if ((K>>j)&1) {
co[i]+=cost[magic[i]][j];
magic[i]=dp[magic[i]][j];
}
}
//for (int i=0;i<=m;++i)
// printf("i=%d nxti=%d magici=%d coi=%I64d\n",i,nxt[i],magic[i],co[i]);
/*
for (int j=0;j<2;++j)
for (int i=0;i<=m;++i)
printf("%d%c",dp[i][j],i==m?'\n':' ');
for (int j=0;j<2;++j)
for (int i=0;i<=m;++i)
printf("%I64d%c",cost[i][j],i==m?'\n':' ');
*/
memset(d,0x3f,sizeof d);
int s=getid(1,0,0);
d[s]=1;
//printf("s=%d\n",s);
que.push(pli(d[s],s));
for (int i=0;i<(int)G[1].size();++i) {
//printf("v=%d u=%d %I64d\n",v[G[1][i].id],u[G[1][i].id],co[G[1][i].id]);
if (v[G[1][i].id]==n)
d[m]=1;
s=magic[G[1][i].id];
if (co[G[1][i].id]<d[s]) {
d[s]=co[G[1][i].id]+1;
que.push(pli(d[s],s));
}
}
while (!que.empty()) {
int o=que.top().second;
long long c=que.top().first;
que.pop();
if (c>d[o])
continue;
//printf("%d %d %I64d\n",u[o],v[o],c);
int p=nxt[o];
if (d[p]>d[o]+1) {
d[p]=d[o]+1;
que.push(pli(d[p],p));
}
int e=v[o];
for (int i=0;i<(int)G[e].size();++i) {
p=magic[G[e][i].id];
if (d[p]>d[o]+co[G[e][i].id]+1) {
d[p]=d[o]+co[G[e][i].id]+1;
que.push(pli(d[p],p));
}
}
}
//for (int i=0;i<=m;++i)
// printf("%I64d%c",d[i],i==m?'\n':' ');
long long res=inf;
for (int i=0;i<=m;++i)
if (v[i]==n)
res=min(res,d[i]);
printf("Case #%d: %I64d\n",cas,res==inf?-1:res);
}
return 0;
}
/*
1
9 10 5
1 7 42
2 5 19
5 8 3
3 4 78
4 7 59
8 1 27
6 3 88
8 3 17
4 9 46
6 8 15
*/
/*
5
5 4 100
1 2 1
2 3 3
2 4 10
4 5 10
3 2 2
1 2 1
1 3 4
5 5 1
1 2 1
2 3 2
3 4 3
2 4 4
4 5 5
5 6 1
1 2 1
2 3 1
3 4 1
4 5 1
5 2 1
5 1 1
5 6 1
1 2 1
2 5 1
1 3 1
3 4 1
4 5 1
2 3 1
*/