2 条题解

  • 0
    @ 2026-6-14 14:46:40

    // Kruskal 重构树 O(MlogM+NlogN)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=20005,M=50005; //重构树 点数=2N,边数=4N
    int idx,h[N],to[M],ne[M];
    void add(int u,int v){
      to[++idx]=v;ne[idx]=h[u];h[u]=idx;
      to[++idx]=u;ne[idx]=h[v];h[v]=idx;
    }
    int n,m,q,p,val[N]; //val新建点点权
    struct E{int x,y,w;}e[M]; //原图边
    int pa[N]; //并查集数组
    int dep[N],fa[N][21]; //树上倍增数组
    
    int find(int x){ //并查集查找
      return pa[x]==x?x:pa[x]=find(pa[x]);
    }
    void kruskal(){
      for(int i=1;i<=n;++i) pa[i]=i;
      sort(e+1,e+1+m,[&](E a,E b){return a.w>b.w;});
      
      for(int i=1;i<=m;++i){
        int x=find(e[i].x),y=find(e[i].y);
        if(x!=y){
          val[++p]=e[i].w; //新建点点权=边权
          pa[p]=pa[x]=pa[y]=p; //点x,y均指向点p
          add(p,x); add(p,y);  //x,y均与p连无向边
        }
      }
    }
    void dfs(int x,int f){ //预处理dep,fa数组
      dep[x]=dep[f]+1; fa[x][0]=f;
      for(int i=1;i<=20;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
      for(int i=h[x];i;i=ne[i]){
        int y=to[i];
        if(y!=f) dfs(y,x);
      }
    }
    int lca(int x,int y){ //倍增求lca
      if(dep[x]<dep[y]) swap(x,y); //让x更深
      for(int i=20;i>=0;i--)if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; //x向上跳到y的同一层
      if(x==y) return x;
      for(int i=20;i>=0;i--)if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; //x,y一起向上跳
      return fa[x][0];
    }
    int main(){
      ios::sync_with_stdio(0);cin.tie(0);
      cin>>n>>m;
      for(int i=1,u,v,w;i<=m;++i){
        cin>>u>>v>>w;
        e[i]={u,v,w};
      }
      
      cin>>q;
      p=n;       //新建点编号初值
      kruskal(); //重构森林
      for(int i=1;i<=n;++i)if(!dep[i]){ //图可能是个森林
        dfs(find(i),0); //预处理dep,fa数组
      }
      for(int u,v;q--;){
        cin>>u>>v;
        if(find(u)!=find(v)) printf("-1\n");
        else printf("%d\n",val[lca(u,v)]);
      }
    }
    
    • 0
      @ 2025-10-8 16:50:15
      #include<bits/stdc++.h>
      //(只取部分有用的输入数据,使得图变成一棵树)
      using namespace std;
      struct edge{ int x,y,pre;}a[21100];int alen,last[11100];
      void ins(int x,int y){alen++;a[alen]=edge{x,y,last[x]};last[x]=alen;}
      
      struct tnode{int f,dep,son,c,z,tp;}t[11100];
      void dfs1(int x,int f)
      {
      	t[x]={f,t[f].dep+1,0,1,0,0};
      	for(int k=last[x];k>0;k=a[k].pre)
      	{
      		int y=a[k].y;
      		if(y!=f)
      		{
      			dfs1(y,f);
      			t[x].c+=t[y].c;
      			if(t[t[x].son].c<t[y].c) t[x].son=y;
      		}
      	}
      }
      int z, ys[11100];
      void dfs2(int x,int tp)
      {
      	++z;t[x].z=z;t[x].tp=tp;ys[z]=x;
      	if(t[x].son!=0) dfs2(t[x].son,tp);
      	for(int k=last[x];k>0;k=a[k].pre)
      	{int y=a[k].y;
      		if(y!=t[x].f && y!=t[x].son)
      			dfs2(y,y);
      	}
      }
      struct trnode{int l,r,lc,rc,c;}tr[21100];int trlen;
      void bt(int l,int r)
      {
      	trlen++;int now=trlen;
      	tr[now]={l,r,-1,-1,0x3f3f3f3f};
      	if(l==r) tr[now].c=0x3f3f3f3f;
      	else
      	{
      		int mid=(l+r)/2;tr[now].lc=trlen+1;bt(l,mid);
      		tr[now].rc=trlen+1;bt(mid+1,r);
      		tr[now].c=min(tr[tr[now].lc].c,tr[tr[now].rc].c);
      	}
      }
      void change(int now,int x,int c)
      {
      	if(tr[now].l==tr[now].r){ tr[now].c=c;return ;}
      	int mid=(tr[now].l+tr[now].r)/2,lc=tr[now].lc,rc=tr[now].rc;
      	if(x<=mid) change(lc,x,c);
      	else       change(rc,x,c);
      	tr[now].c=min(tr[lc].c,tr[rc].c);
      }
      int findmin(int now,int l,int r)
      {
      	if(tr[now].l==l && tr[now].r==r) return tr[now].c;
      	int mid=(tr[now].l+tr[now].r)/2,lc=tr[now].lc,rc=tr[now].rc;
      	if(r<=mid)        return findmin(lc,l,r);
      	else if(l>=mid+1) return findmin(rc,l,r);
      	else              return min(findmin(lc,l,mid),findmin(rc,mid+1,r));
      }
      int solve(int x,int y)
      {
      	int ans=0x3f3f3f3f;
      	while(t[x].tp!=t[y].tp)
      	{
      		if(t[t[x].tp].dep>t[t[y].tp].dep)swap(x,y);
      		ans=min(ans,findmin(1,t[t[y].tp].z,t[y].z));
      		y=t[t[y].tp].f;
      	}
      	if(x==y) return ans;
      	if(t[x].dep>t[y].dep)swap(x,y);
      	ans=min(ans,findmin(1,t[t[x].son].z,t[y].z));
      	return ans;
      }
      
      struct node{int x,y,c;}e[5100];bool v[51100];
      bool cmp(node e1,node e2){ return e1.c>e2.c;}  
      int fa[11100];
      int findfa(int x){ return fa[x]=(fa[x]==x)?fa[x]:findfa(fa[x]);}
      int main()
      {
      	int n,m;scanf("%d%d",&n,&m);
      	for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].c);
      	sort(e+1,e+m+1,cmp);
      	for(int i=1;i<=n;i++)fa[i]=i;
      	memset(v,0,sizeof(v));int s=0;
      	for(int i=1;i<=m;i++)
      	{
      		int tx=findfa(e[i].x),ty=findfa(e[i].y);
      		if(tx!=ty)
      		{
      			v[i]=1;fa[tx]=ty;s++;if(s==n-1)break;
      		}
      	}
      
      	alen=0;memset(last,0,sizeof(last));
      	for(int i=1;i<=m;i++)if(v[i]) ins(e[i].x,e[i].y),ins(e[i].y,e[i].x);
      	
      	t[0]={0,0,0,0,0,0}; dfs1(1,0);
      	z=0; dfs2(1,1);
      	trlen=0;bt(1,z);
      	for(int i=1;i<=m;i++)if(v[i])
      	{
      		if(t[e[i].x].dep>t[e[i].y].dep) swap(e[i].x,e[i].y);
      		change(1,t[e[i].y].z,e[i].c);
      	}
      	
      	int q;scanf("%d",&q);	
      	for(int i=1;i<=q;i++) 
      	{
      		int x,y; scanf("%d%d",&x,&y);if(findfa(x)!=findfa(y)) printf("-1\n");
      		else printf("%d\n",solve(x,y)); 
      	}
      	return 0; 
      }
      
      • 1

      D147 Kruskal 重构树[NOIP 2013 提高组] 货车运输

      信息

      ID
      361
      时间
      1000ms
      内存
      128MiB
      难度
      4
      标签
      递交数
      93
      已通过
      40
      上传者