题解 P1967 【货车运输】
写一个树剖的题解吧
先分析下题意,一个图,若干点,若干边,查询若干链
首先,很清楚,最大生成树
这样得到若干棵树
然后,建一个虚根,将这些树变成一棵树
查询的话,就是一条链上的各边的最小值,树剖,然后线段树维护rmq
另,树剖维护点权,而该题给的是边权,所以要转换一下
我是这样做的,定义一个点的点权为为其到其父节点的边权,根节点就是无穷大
代码如下,不喜勿喷:
#include<iostream>
#include<algorithm>
using namespace std;
struct ed
{
int v,x,y;
};
ed e[500008];
int n,m;
bool cmp(const ed &a,const ed &b)
{
return a.v>b.v;
}
int hea[50005],nex[30005],poi[30005],val[30005],tot;
void work(int i,int j,int v)
{
tot++;
val[tot]=v;
poi[tot]=j;
nex[tot]=hea[i];
hea[i]=tot;
}
int fa[50005],dep[50005],top[50005],size[50005],xl[50005],num,pos[50005],son[50005];
int fd(int x)
{
if(fa[x]!=x)
fa[x]=fd(fa[x]);
return fa[x];
}
int dc[50005];
int s[400005];
void build(int p,int l,int r)
{
if(l==r)
{
s[p]=dc[xl[l]];
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build((p<<1)|1,mid+1,r);
s[p]=min(s[p<<1],s[(p<<1)|1]);
}
int getmin(int p,int l,int r,int al,int ar)
{
if(l>=al&&r<=ar)
{
return s[p];
}
int minn=372199;
int mid=(l+r)>>1;
if(al<=mid)
minn=min(minn,getmin(p<<1,l,mid,al,ar));
if(ar>mid)
minn=min(minn,getmin((p<<1)|1,mid+1,r,al,ar));
return minn;
}
void dfs1(int node)
{
int b=hea[node];
while(b)
{
int u=poi[b];
if(u==fa[node])
{
b=nex[b];
continue;
}
size[u]=1;
fa[u]=node;
dc[u]=val[b];
dep[u]=dep[node]+1;
dfs1(u);
size[node]+=size[u];
if(size[son[node]]<size[u])
son[node]=u;
b=nex[b];
}
}
void dfs2(int node)
{
num++;
pos[node]=num,xl[num]=node;
if(son[node])
{
top[son[node]]=top[node];
dfs2(son[node]);
}
int b=hea[node];
while(b)
{
int u=poi[b];
if(u==son[node]||u==fa[node])
{
b=nex[b];
continue;
}
top[u]=u;
dfs2(u);
b=nex[b];
}
}
int query(int x,int y)
{
int minn=372199;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
int t=x;
x=y;
y=t;
}
minn=min(minn,getmin(1,1,n+1,pos[top[x]],pos[x]));
x=fa[top[x]];
}
if(x==y)
return minn;
if(dep[x]<dep[y])
{
int t=x;
x=y;
y=t;
}
minn=min(minn,getmin(1,1,n+1,pos[y]+1,pos[x]));
return minn;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>e[i].x>>e[i].y>>e[i].v;
for(int i=1;i<=n;i++)
fa[i]=i;
sort(e+1,e+m+1,cmp);
int rest=n-1;
for(int i=1;i<=m;i++)
{
if(!rest)
break;
int xx=e[i].x,yy=e[i].y;
int fx=fd(xx),fy=fd(yy);
if(fx!=fy)
{
fa[fx]=fy;
work(xx,yy,e[i].v);
work(yy,xx,e[i].v);
}
}
int root=n*3;
for(int i=1;i<=n;i++)
if(fa[i]==i)
{
fa[i]=root;
work(root,i,-1);
}
else
fa[i]=0;
fa[root]=root;
dfs1(root);
dfs2(root);
build(1,1,n+1);
int q;
cin>>q;
for(int i=1;i<=q;i++)
{
int x,y;
cin>>x>>y;
int qq=query(x,y);
cout<<qq<<endl;
}
}