1 条题解

  • 0
    @ 2025-10-8 17:07:23

    scy代码(暴力求LCA 超时,75分):

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5;
    vector<pair<int,int>>G1[N],G2[N<<1];
    
    int tsp,cnt,dfn[N],low[N];
    stack<int>stk;
    int rng[N<<1],w[N],tw[N];
    
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tsp;
        stk.push(x);
        for(auto i:G1[x])
        {
            int y=i.first,c=i.second;
            if(!dfn[y])
            {
                w[y]=w[x]+c;
                tarjan(y);
                low[x]=min(low[x],low[y]);
    			if(dfn[x]==low[y])
                {
                	++cnt;//新增方点的编号
                	G2[x].push_back({cnt,0});
    				rng[cnt]=w[stk.top()]-w[x] +  tw[stk.top()];//新增方点所代表的环的周长
                	for(int z=-1;z!=y;)
    				{
    					z=stk.top();stk.pop();
    					G2[cnt].push_back({z,min(w[z]-w[x],rng[cnt]-(w[z]-w[x]))});
    				}
    				
                }  
            }
            else if(low[x]>dfn[y]) tw[x]=c,low[x]=dfn[y];
        }
    }
    int n,dep[N<<1],d[N<<1],up[N<<1];
    void dfs(int x)
    {
        for(auto i:G2[x])
        {
            int y=i.first,c=i.second;
            d[y]=d[x]+c;
            dep[y]=dep[x]+1;
            up[y]=x;
            dfs(y);
        }
    }
    int dist(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        int A=x,B=y;
        while(dep[x]>dep[y]) x=up[x];
        if(x==y) return d[A]-d[ B ];
        while(up[x]!=up[y])x=up[x],y=up[y];
        int lca=up[x];//或者 lca=up[y]
        if(lca<=n) return d[A]+d[ B ]-2*d[lca];
        else       return d[A]+d[ B ]-d[x]-d[y]
    	                  +min( abs(w[x]-w[y]) , rng[lca]-abs(w[x]-w[y]) );
    }
    int main()
    {
        int m,q;scanf("%d%d%d",&n,&m,&q);
        for(int i=1,x,y,c;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&c);
            G1[x].push_back({y,c});
            G1[y].push_back({x,c});
        }
        tsp=0;cnt=n;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
        tarjan(1),stk.pop();//洁癖,最后1还在栈中
        memset(dep,0,sizeof(dep));memset(d,0,sizeof(d));memset(up,0,sizeof(up));
    	dfs(1);
        while(q--)
        {
            int x,y;scanf("%d%d",&x,&y);
            printf("%d\n",dist(x,y));
        }
        return 0;
    }
    

    scy代码(标程:st表求LCA 100分):

    #include<bits/stdc++.h>
    using namespace std;
    const int N=5e5;
    vector<pair<int,int>>G1[N],G2[N<<1];
    int tsp,cnt,dfn[N],low[N];
    stack<int>stk;
    int rng[N<<1],w[N],tw[N];
    
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tsp;
        stk.push(x);
        for(auto i:G1[x])
        {
            int y=i.first,c=i.second;
            if(!dfn[y])
            {
                w[y]=w[x]+c;
                tarjan(y);
                low[x]=min(low[x],low[y]);
    			if(dfn[x]==low[y])
                {
                	++cnt;
    				G2[x].push_back({cnt,0});
    				rng[cnt]=w[stk.top()]-w[x] +  tw[stk.top()];
                	for(int z=-1;z!=y;)
    				{
    					z=stk.top();stk.pop();
    					G2[cnt].push_back({z,min(w[z]-w[x],rng[cnt]-(w[z]-w[x]))});
    				}
    				
                }  
            }
            else if(low[x]>dfn[y]) tw[x]=c,low[x]=dfn[y];
        }
    }
    int n,D,dep[N<<1],d[N<<1],st[N<<1][20];
    void dfs(int x)
    {
        for(auto i:G2[x])
        {
            int y=i.first,c=i.second;
            d[y]=d[x]+c;
    		dep[y]=dep[x]+1;
    		st[y][0]=x;for(int i=1;i<=D;i++)st[y][i]=st[st[y][i-1]][i-1];
            dfs(y);
        }
    }
    int dist(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        int A=x,B=y;
        for(int i=D;i>=0;i--)if(dep[st[x][i]]>=dep[y]) x=st[x][i];
        if(x==y) return d[A]-d[ B ];
        for(int i=D;i>=0;i--)if(st[x][i]!=st[y][i])x=st[x][i],y=st[y][i];
        int lca=st[x][0];
    
        if(lca<=n) return d[A]+d[ B ]-2*d[lca];
        else       return d[A]+d[ B ]-d[x]-d[y]
    	                  +min( abs(w[x]-w[y]) , rng[lca]-abs(w[x]-w[y]) );
    }
    int main()
    {
        int m,q;scanf("%d%d%d",&n,&m,&q);
        for(int i=1,x,y,c;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&c);
            G1[x].push_back({y,c});
            G1[y].push_back({x,c});
        }
        tsp=0;cnt=n;memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));
        tarjan(1),stk.pop();
        D=log2(cnt);memset(dep,0,sizeof(dep));memset(d,0,sizeof(d));memset(st,0,sizeof(st));
    	dfs(1);
        while(q--)
        {
            int x,y;scanf("%d%d",&x,&y);
            printf("%d\n",dist(x,y));
        }
        return 0;
    }
    

    D31 圆方树 P5236【模板】静态仙人掌(这个视频不推荐)
    视频中的代码(同样不推荐):

    // Tarjan+倍增 O((n+m)logn)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=20000,M=N*3;
    int n,m,Q;
    struct edge{int v,w,ne;}e[M];
    int h1[N],h2[N],idx=1;//建图
    int dfn[N],low[N],tim;//tarjan
    int s[N],sc[N],fa[N],fw[N],fe[N],cn;
    int f[N][14],dep[N],d[N];//lca
    int A,B;//存lca的两个儿子
    
    void add(int h[],int a,int b,int c){
      e[++idx]={b,c,h[a]};h[a]=idx;
    }
    void build_tree(int u,int v,int w){
      int sum=w;
      for(int k=v;k!=u;k=fa[k]){
        s[k]=sum; //u...k的环长
        sum+=fw[k]; //前缀和
      }
      // s[u]=sc[u]=sum;
      add(h2,u,++cn,0);
      for(int k=v;k!=u;k=fa[k]){
        sc[k]=sum; //总环长
        add(h2,cn,k,min(s[k],sum-s[k]));
      }
    }
    void tarjan(int u,int ine){
      dfn[u]=low[u]=++tim;
      for(int i=h1[u];i;i=e[i].ne){
        int v=e[i].v,w=e[i].w;
        if(!dfn[v]){ //若没有访问
          //fw:存边权,fe:存入边
          fa[v]=u,fw[v]=w,fe[v]=i;
          tarjan(v,i);
          low[u]=min(low[u],low[v]);
          if(dfn[u]<low[v]) //非环边
            add(h2,u,v,w);//直接加边
        }
        else if(i!=(ine^1)) //构成环
          low[u]=min(low[u],dfn[v]);
      }
      for(int i=h1[u];i;i=e[i].ne){
        int v=e[i].v,w=e[i].w;
        if(dfn[u]<dfn[v]&&fe[v]!=i)
          build_tree(u,v,w); //建树
      }
    }
    void dfs(int u,int father){
      dep[u]=dep[father]+1;
      f[u][0]=father;
      for(int k=1;k<=13;k++)
        f[u][k]=f[f[u][k-1]][k-1];
      for(int i=h2[u];i;i=e[i].ne){
        int v=e[i].v,w=e[i].w;
        d[v]=d[u]+w;
        dfs(v,u);
      }
    }
    int lca(int u,int v){
      if(dep[u]<dep[v]) swap(u,v);
      for(int k=13;k>=0;k--)
        if(dep[f[u][k]]>=dep[v])
          u=f[u][k];
      if(u==v) return u;
      for(int k=13;k>=0;k--)
        if(f[u][k]!=f[v][k]){
          u=f[u][k];
          v=f[v][k];
        }
      A=u,B=v;//存lca的两个儿子
      return f[u][0];
    }
    int main(){
      scanf("%d%d%d",&n,&m,&Q);
      cn=n;
      while(m--){
        int a,b,c;scanf("%d%d%d",&a,&b,&c);
        add(h1,a,b,c),add(h1,b,a,c);
      }
      tarjan(1,-1);//找环建树
      dfs(1,0);//lca打表
      while(Q--){
        int u,v;
        scanf("%d%d",&u,&v);
        int p=lca(u,v);//找lca
        if(p<=n) //若是圆点
          printf("%d\n",d[u]+d[v]-d[p]*2);
        else{ //若是方点
          int len=abs(s[A]-s[B]);
          int dAB=min(len,sc[A]-len);
          int dis=dAB+d[u]-d[A]+d[v]-d[B];
          printf("%d\n",dis);
        }
      }
    }
    
    • 1

    信息

    ID
    4712
    时间
    300ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者