生活随笔
收集整理的這篇文章主要介紹了
SDOI2015 寻宝游戏
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
傳送門
這題最關(guān)鍵的一點(diǎn)是要想清楚這個(gè)路徑長(zhǎng)度是咋算的。
要注意到他是走到所有關(guān)鍵點(diǎn)去取寶藏然后回來。我們假想這些關(guān)鍵點(diǎn)構(gòu)成一棵虛樹,那么這就相當(dāng)于是虛樹上的一個(gè)dfsdfsdfs。
當(dāng)關(guān)鍵點(diǎn)確定的時(shí)候,其實(shí)最短路徑長(zhǎng)就確定了,也就是在虛樹上從一個(gè)點(diǎn)開始dfs直到到回到這個(gè)節(jié)點(diǎn)所經(jīng)過的路徑長(zhǎng)之和。起點(diǎn)其實(shí)無所謂,不選虛樹外面的點(diǎn)就行。
如果我們把虛樹上的點(diǎn)按照dfs序從小到大排為p1,p2,?,pnp_1,p_2,\cdots,p_np1?,p2?,?,pn?,那么這時(shí)候詢問的答案即為:
ans=∑i=1n?1dis(pi,pi+1)+dis(pn,p1)ans=\sum_{i=1}^{n-1} {dis(p_i,p_{i+1})}+dis(p_n,p_1)ans=i=1∑n?1?dis(pi?,pi+1?)+dis(pn?,p1?)
算是計(jì)算樹上路徑和的一種套路吧。
把dfsdfsdfs序從小到大排列,可以想象成是一個(gè)環(huán),要求支持在這個(gè)環(huán)上加點(diǎn),刪點(diǎn),求權(quán)值和。
發(fā)現(xiàn)這個(gè)東西用setsetset維護(hù)就行了。每次找到前驅(qū)后繼把權(quán)值改一改即可。要注意一下插入的是dfsdfsdfs序。
#include<bits/stdc++.h>
#define cs const
#define re register
#define ll long long
cs
int N
=1e5+10,Log
=17;
int Head
[N
],Next
[N
<<1],V
[N
<<1],cnt
=0;
int dfn
[N
],t
[N
],key
[N
],dep
[N
],f
[N
][Log
],tot
=0;
int n
,m
,x
,y
,pos
;ll z
,W
[N
<<1],dis
[N
];
std
::set
<int> S
;
typedef std
::set
<int>::iterator It
;
namespace IO
{cs
int Rlen
=1<<22|1;char buf
[Rlen
],*p1
,*p2
;inline char gc(){return (p1
==p2
)&&(p2
=(p1
=buf
)+fread(buf
,1,Rlen
,stdin),p1
==p2
)?EOF:*p1
++;}template<typename T
>inline T
get(){char ch
;T x
;while(!isdigit(ch
=gc()));x
=ch
^48;while(isdigit(ch
=gc())) x
=((x
+(x
<<2))<<1)+(ch
^48);return x
;}inline int gi(){return get
<int>();}inline ll
gl(){return get
<ll
>();}
}
using namespace IO
;
inline void add(int u
,int v
,ll w
){Next
[++cnt
]=Head
[u
],V
[cnt
]=v
,W
[cnt
]=w
,Head
[u
]=cnt
;}
inline void dfs(int u
,int fa
){t
[dfn
[u
]=++tot
]=u
,f
[u
][0]=fa
,dep
[u
]=dep
[fa
]+1;for(int re i
=1;i
<Log
;++i
) f
[u
][i
]=f
[f
[u
][i
-1]][i
-1];for(int re i
=Head
[u
],v
=V
[i
];i
;v
=V
[i
=Next
[i
]])if(v
!=fa
) dis
[v
]=dis
[u
]+W
[i
],dfs(v
,u
);
}
inline int lca(int u
,int v
){if(dep
[u
]<dep
[v
]) std
::swap(u
,v
);for(int re i
=Log
-1;~i
;--i
) if(dep
[f
[u
][i
]]>=dep
[v
]) u
=f
[u
][i
];if(u
==v
) return u
;for(int re i
=Log
-1;~i
;--i
) if(f
[u
][i
]!=f
[v
][i
]) u
=f
[u
][i
],v
=f
[v
][i
];return f
[u
][0];
}
inline ll
dist(int u
,int v
){return dis
[u
]+dis
[v
]-2ll*dis
[lca(u
,v
)];}
inline int pre(int u
){It p
=S
.lower_bound(u
);if(p
==S
.begin()) return t
[*--S
.end()];return t
[*--p
];
}
inline int nxt(int u
){It p
=S
.lower_bound(u
);if(++p
==S
.end()) return t
[*S
.begin()];return t
[*p
];
}
ll ans
=0;
int main(){
n
=gi(),m
=gi();for(int re i
=1;i
<n
;++i
)x
=gi(),y
=gi(),z
=gl(),add(x
,y
,z
),add(y
,x
,z
);dfs(1,0);while(m
--){pos
=gi();if(!key
[pos
]){key
[pos
]^=1,S
.insert(dfn
[pos
]),x
=pre(dfn
[pos
]),y
=nxt(dfn
[pos
]);ans
+=dist(x
,pos
)+dist(y
,pos
)-dist(x
,y
);}else{key
[pos
]^=1,x
=pre(dfn
[pos
]),y
=nxt(dfn
[pos
]);ans
-=dist(x
,pos
)+dist(y
,pos
)-dist(x
,y
);S
.erase(dfn
[pos
]);}printf("%lld\n",ans
);}
}
總結(jié)
以上是生活随笔為你收集整理的SDOI2015 寻宝游戏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。