题目描述
sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好。为了方便起见,我们可以认为宇宙是一张有N 个顶点和M 条边的带权无向图,顶点表示各个星系,两个星系之间有边就表示两个星系之间可以直航,而边权则是航行的危险程度。
sideman 现在想把危险程度降到最小,具体地来说,就是对于若干个询问(A, B),sideman 想知道从顶点A 航行到顶点B 所经过的最危险的边的危险程度值最小可能是多少。作为sideman 的同学,你们要帮助sideman 返回家园,兼享受安全美妙的宇宙航行。所以这个任务就交给你了。
输入输出格式
输入格式:第一行包含两个正整数N 和M,表示点数和边数。
之后 M 行,每行三个整数A,B 和L,表示顶点A 和B 之间有一条边长为L 的边。顶点从1 开始标号。
下面一行包含一个正整数 Q,表示询问的数目。
之后 Q 行,每行两个整数A 和B,表示询问A 和B 之间最危险的边危险程度的可能最小值。
对于每个询问, 在单独的一行内输出结果。如果两个顶点之间不可达, 输出impossible。
输入输出样例
4 5 1 2 5 1 3 2 2 3 11 2 4 6 3 4 4 3 2 3 1 4 1 2
5 4 5
说明
对于40% 的数据,满足N≤1000,M≤3000,Q≤1000。
对于 80% 的数据,满足N≤10000,M≤105,Q≤1000。
对于 100% 的数据,满足N≤105,M≤3×105,Q≤105,L≤109。数据不保证没有重边和自环。
LCT大法好!
首先一发最小生成树。
添加一条 u->v 的边,权值为w,那么就相当于:
link(u,id);link(v,id);//id是边的序号
value[id]=w;
然后就是板子了。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 300010
using namespace std;
int n,m,q;
int w[MAXN<<1],fa[MAXN];
int top,stack[MAXN<<1];
struct node1{
int f,flag,son[2];
int v;
}a[MAXN<<1];
struct node2{
int u,v,w;
}b[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
bool cmp(const node2 &x,const node2 &y){
return x.w<y.w;
}
inline bool isroot(int rt){
return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
}
inline void pushup(int rt){
if(!rt)return;
a[rt].v=rt;
if(w[a[rt].v]<w[a[a[rt].son[0]].v])a[rt].v=a[a[rt].son[0]].v;
if(w[a[rt].v]<w[a[a[rt].son[1]].v])a[rt].v=a[a[rt].son[1]].v;
}
inline void pushdown(int rt){
if(!rt||!a[rt].flag)return;
a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
swap(a[rt].son[0],a[rt].son[1]);
}
inline void turn(int rt){
int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
if(!isroot(x)){
if(a[y].son[0]==x)a[y].son[0]=rt;
else a[y].son[1]=rt;
}
a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
pushup(x);pushup(rt);
}
void splay(int rt){
top=0;
stack[++top]=rt;
for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
while(top)pushdown(stack[top--]);
while(!isroot(rt)){
int x=a[rt].f,y=a[x].f;
if(!isroot(x)){
if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
else turn(x);
}
turn(rt);
}
}
void access(int rt){
for(int i=0;rt;i=rt,rt=a[rt].f){
splay(rt);
a[rt].son[1]=i;
pushup(rt);
}
}
inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void link(int x,int y){makeroot(x);a[x].f=y;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void uniun(int x,int y){x=find(x);y=find(y);if(x!=y)fa[y]=x;}
void kruskal(){
int s=0;
for(int i=1;i<=n;i++){
fa[i]=i;
a[i].v=i;
w[i]=0;
}
sort(b+1,b+m+1,cmp);
for(int i=1;i<=m;i++){
w[i+n]=b[i].w;
a[i+n].v=i+n;
}
for(int i=1;i<=m&&s<n-1;i++)
if(find(b[i].u)!=find(b[i].v)){
uniun(b[i].u,b[i].v);
link(b[i].u,i+n);
link(b[i].v,i+n);
s++;
}
}
void work(){
int x,y;
q=read();
while(q--){
x=read();y=read();
if(find(x)!=find(y)){
printf("impossible\n");
continue;
}
split(x,y);
printf("%d\n",w[a[y].v]);
}
}
void init(){
n=read();m=read();
for(int i=1;i<=m;i++){b[i].u=read();b[i].v=read();b[i].w=read();}
kruskal();
}
int main(){
init();
work();
return 0;
}