luogu题解P1967货车运输--树链剖分
题目链接
https://www.luogu.org/problemnew/show/P1967
分析
NOIp的一道裸题,直接在最大生成树上剖分取最小值一下就完事了,非常好写,常数也比较小,然而题解里有许多我没见过的船新操作,先挖个坑等有时间再看
注意
-
树链剖分又在第一遍挂了,忘了写top[now]=t;
-
注意题目说明并没有保证是联通的!!!然后成功被Hack了.这真的要警惕,指不定哪天毒瘤出题人就在这里把你正解卡成60(flag++)
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
#include <queue>
#define ll long ong
#define ri register int
#define ull unsigned long long
using std::vector;
using std::swap;
using std::min;
using std::max;
using std::sort;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return ;
}
const int maxn=10005;
const int maxm=50005;
const int inf=0x7fffffff;
int n,m;
struct Edge{
int x,y,c;
Edge(int _x,int _y,int _c){x=_x,y=_y,c=_c;}
Edge(){x=y=c=0;}
bool operator <(const Edge &b)const {
return c>b.c;
}
}edge[maxm];
struct Dat{
int ver,dis;
Dat(int x,int y){ver=x,dis=y;}
Dat(){;}
};
vector<Dat>g[maxn];
int pa[maxn];
int get(int x){
if(pa[x]!=x)pa[x]=get(pa[x]);//return pa[x]==x?pa[x]:pa[x]=get(pa[x]);
return pa[x];
}
inline void kruskal(){
int cnt=0,x,y,xx,yy,c;
sort(edge+1,edge+1+m);
for(ri i=1;i<=n;i++)pa[i]=i;
for(ri i=1;i<=m;i++){
//printf("%d\n",edge[i].c);
int x=edge[i].x,y=edge[i].y;
xx=get(x),yy=get(y);
if(xx==yy)continue;
c=edge[i].c;
//printf("%d %d %d\n",x,y,c);
g[x].push_back(Dat(y,c));
g[y].push_back(Dat(x,c));
pa[xx]=yy;
cnt++;
if(cnt==n-1)break;
}
return ;
}
int dep[maxn],son[maxn],top[maxn],size[maxn],dfn[maxn],fa[maxn],rnk[maxn],tot=0;
int w[maxn];
void dfs_1(int now){
int v;size[now]=1;
for(ri i=0;i<g[now].size();i++){
v=g[now][i].ver;
if(v==fa[now])continue;
fa[v]=now,dep[v]=dep[now]+1;
w[v]=g[now][i].dis;
dfs_1(v);
size[now]+=size[v];
if(!son[now]||size[v]>size[son[now]])son[now]=v;
}
return ;
}
void dfs_2(int now,int t){
int v;dfn[now]=++tot,rnk[tot]=now,top[now]=t;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=0;i<g[now].size();i++){
v=g[now][i].ver;
if(v==fa[now]|v==son[now])continue;
dfs_2(v,v);
}
return ;
}
int mi[maxn<<2];
void build(int now,int l,int r){
if(l==r){
mi[now]=w[rnk[l]];
return ;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
mi[now]=min(mi[now<<1],mi[now<<1|1]);
return ;
}
int L,R;
int query(int now,int l,int r){
if(L<=l&&r<=R){
return mi[now];
}
int ans=inf,mid=(l+r)>>1;
if(L<=mid)ans=min(ans,query(now<<1,l,mid));
if(mid<R)ans=min(ans,query(now<<1|1,mid+1,r));
return ans;
}
inline int query_path(int x,int y){
int ans=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
L=dfn[top[x]],R=dfn[x];
ans=min(ans,query(1,1,n));
x=fa[top[x]];
}
if(dfn[x]>dfn[y])swap(x,y);
L=dfn[x]+1,R=dfn[y];
if(L>R)return ans;
ans=min(ans,query(1,1,n));
return ans;
}
int main(){
int q,x,y,z;
read(n),read(m);
for(ri i=1;i<=m;i++){
read(x),read(y),read(z);
edge[i]=Edge(x,y,z);
}
kruskal();
for(ri i=1;i<=n;i++){//不一定联通
if(!dfn[i]){
dep[i]=1,fa[i]=0;
dfs_1(i);
dfs_2(i,i);
}
}
build(1,1,n);
read(q);
while(q--){
read(x),read(y);
int tmp=query_path(x,y);
if(!tmp)puts("-1");
else printf("%d\n",tmp);
}
return 0;
}