开始在某谷上刷题,点了下标签发现是图上倍增,然后我:.....图上怎么倍增?
彳亍口巴,倍增就倍增吧,看看倍增怎么搞
然后十分钟过去了....
我:.......还是打数据结构吧
数据结构什么的果然是弱者的福音!(被数据结构送退役预定)
思路:
1.用个并查集维护哪些点在同一个连通块里面,把每个连通块向其余联通块连一个权值为-1的边(因为一个连通块之间是可以相互到达的,所以只用连一个边就可以啦...)
2.用prim跑最大生成树,因为要求最小值最大嘛...所以尽量跑最大边啦,跑的时候记录一下每个节点是从哪个节点拓展来的,建立新的树,方便下面跑树剖
3.树上路径最小值~典型的树剖套路题嗯呐
码量偏大,注意一下初始化细节qwq,数据结构好像但也很容易打挂就是了orz
传送门:https://www.luogu.org/problemnew/show/P1967
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <queue>
#define inf 1e9
#define maxn 10100
#define maxm 50100
using namespace std;
bool vis[maxn];
int n,m,q,u,v,w,num,indx,sum;
int mini[maxm],ll[maxm],rr[maxm],s[maxn],a[maxn];
int fa[maxn],dis[maxn],dep[maxn],sz[maxn],wson[maxn]fir[maxn],;
int dfn[maxn],node[maxn],head[maxn],from[maxn],to[maxn],val[maxn];
struct qwq
{
int to,nxt,val;
}e[maxm<<1];
struct nod
{
int u,d,f;
bool operator < (const nod &a)const
{
return d<a.d;
}
};
priority_queue<nod> que;
int read()
{
int xx=0,kk=1;char ch=' ';
while(!isdigit(ch)){ch=getchar();if(ch=='-')kk=-1;}
while(isdigit(ch)){xx=xx*10+ch-'0';ch=getchar();}
return kk*xx;
}
void addedge(int u,int v,int w)
{
e[++num].to=v;
e[num].val=w;
e[num].nxt=fir[u];
fir[u]=num;
}
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
x=find(x);y=find(y);
if(x!=y) fa[x]=y;
}
void prim(int u)
{
vis[u]=true;
for(int i=fir[u];i;i=e[i].nxt)
{
int v=e[i].to;
dis[v]=max(dis[v],e[i].val);
if(!vis[v]) que.push((nod){v,dis[v],u});
}
while(!que.empty())
{
nod tmp=que.top();que.pop();
int v=tmp.u,d=tmp.d,f=tmp.f;
if(dis[v]==d&&!vis[v])
{
from[++sum]=f;to[sum]=v;
val[sum]=d;prim(v);
break;
}
}
}
void build(int l,int r,int num)
{
ll[num]=l,rr[num]=r;
if(l==r){mini[num]=a[node[l]];return;}
int mid=(l+r)>>1;
build(l,mid,num<<1);
build(mid+1,r,num<<1|1);
mini[num]=min(mini[num<<1],mini[num<<1|1]);
}
int query(int l,int r,int num)
{
if(l>rr[num]||r<ll[num]||l>r) return inf;
if(ll[num]>=l&&rr[num]<=r) return mini[num];
return min(query(l,r,num<<1),query(l,r,num<<1|1));
}
int qmin(int x,int y)
{
int tmp=inf;
while(head[x]!=head[y])
{
if(dep[head[x]]<dep[head[y]]) swap(x,y);
tmp=min(tmp,query(dfn[head[x]],dfn[x],1)),x=fa[head[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return min(tmp,query(dfn[x]+1,dfn[y],1));
}
void dfs1(int u,int f)
{
dep[u]=dep[f]+1,sz[u]=1,fa[u]=f;
for(int i=fir[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa[u]) continue;
dfs1(v,u);
sz[u]+=v;a[v]=e[i].val;
if(sz[v]>sz[wson[u]]) wson[u]=v;
}
}
void dfs2(int u,int top)
{
dfn[u]=++indx,node[indx]=u,head[u]=top;
if(wson[u]) dfs2(wson[u],top);
for(int i=fir[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v!=fa[u]&&v!=wson[u]) dfs2(v,v);
}
}
int main()
{
n=read();m=read();
for(int i=0;i<=n;++i) fa[i]=i,dis[i]=-inf;
while(m--)
{
u=read(),v=read(),w=read();
merge(u,v);addedge(u,v,w);addedge(v,u,w);
}
for(int i=1;i<=n;++i)
if(fa[i]==i) s[++sum]=i;
for(int i=1;i<=sum;++i)
for(int j=i+1;j<=sum;++j)
addedge(s[i],s[j],-1),addedge(s[j],s[i],-1);
sum=dis[1]=0;prim(1);num=0;
memset(fir,0,sizeof(fir));
for(int i=1;i<=sum;++i)
addedge(from[i],to[i],val[i]);
dfs1(1,0);dfs2(1,1);a[1]=inf;
build(1,n,1);q=read();
while(q--)
{
u=read(),v=read();
printf("%d\n",qmin(u,v));
}
return 0;
}