您的位置:首页 > 其它

NOIP2013货车运输 计蒜客习题 蒜头君运送宝藏

2018-03-05 13:17 274 查看
手画样例容易发现每次询问所求答案为路径上的最小边
而最大生成树的最小边一定是所有生成树中最大的 且原图的连通性不变
指定每个连通块中的任意一个结点为根建树  可以发现每次询问的货车路径经过他们的LCA
可以在求LCA的同时维护最小边的信息 同样用一个倍增数组 而判断连通可以用并查集
半个周日都献给这题了丂
点击打开链接
#include<bits/stdc++.h>
using namespace std;
const int maxn=10001,maxm=50001,inf=0x3f3f3f3f;
struct e{int u,v,w; bool operator<(const e &a)const{return w>a.w;}}t[maxm];
struct edge{int v,w,nxt;}e[maxm<<1];
int p[maxn],fa[maxn],eid=0,anc[maxn][20],w[maxn][20],d[maxn],n,m,q,rst;
inline int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
inline void dfs(int u){
for(int i=p[u];~i;i=e[i].nxt){
int v=e[i].v;
if(!d[v]){
d[v]=d[u]+1;
anc[v][0]=u;
w[v][0]=e[i].w;
dfs(v);
}
}
}
inline void pre(){
memset(p,-1,sizeof(p));
for(int i=1;i<=n;i++) fa[i]=i;
}
inline void init(){
for(int lv=1;(1<<lv)<=n;lv++)
{
for(int i=1;i<=n;i++)
{
anc[i][lv]=anc[anc[i][lv-1]][lv-1];
w[i][lv]=min(w[anc[i][lv-1]][lv-1],w[i][lv-1]);//倍增维护最小值
}
}
}
inline int lca(int x,int y){
int ans=inf;
if(d[x]<d[y]) swap(x,y);
int i,j;
for(i=0;(1<<i)<=d[x];i++);
i--;
for(int j=i;j>=0;j--)
{
if(d[x]-d[y]>=(1<<j)){
ans=min(ans,w[x][j]); //往上跳并更新w[x][j]
x=anc[x][j];
}
}
if(x==y) return ans;
for(j=i;j>=0;j--){
if(anc[x][j]!=anc[y][j])
{
ans=min(ans,min(w[x][j],w[y][j])); //同时两个往上跳
x=anc[x][j];
y=anc[y][j];
}
}
ans=min(ans,min(w[x][0],w[y][0])); //一步到lca
return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&t[i].u,&t[i].v,&t[i].w);
}
sort(t+1,t+m+1);
pre();
rst=n;
for(int i=1;i<=m;i++)
{
int u=t[i].u,v=t[i].v,w=t[i].w;
int x=get(u),y=get(v);
if(x!=y){
fa[x]=y;
rst--;
e[eid].v=v;e[eid].w=w;e[eid].nxt=p[u];p[u]=eid++;
e[eid].v=u;e[eid].w=w;e[eid].nxt=p[v];p[v]=eid++;
if(rst==1) break; //建图
}
}
for(int i=1;i<=n;i++)
if(d[i]==0){
d[i]=1;
anc[i][0]=0;
dfs(i);
}
init();
cin>>q;
int a,b;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&a,&b);
if(get(a)!=get(b)){
puts("-1");
}
else{
printf("%d\n",lca(a,b));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: