[BeiJing2010组队]次小生成树 Tree 【大规模的严格次小生成树】【犀利版Tarjan】

【题目链接】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1977

【算法分析】

这道题本应该倍增的方法也应该可以AC得,但是时间卡得太紧。。。无奈TLE。

先说这种AC的算法吧。

1、先用kruskal进行MST。

2、如果尝试用一条边去搞进去的话,那么就要求对应两点中那条树链中的最大权边或者次大权边,才能知道假如包含这条边的严格次小生成树是多大。

AC的算法是这么实现的。

这种方法来源于:http://hi.baidu.com/wjbzbmr/blog/item/c3c8ff0455e3c87003088121.html

在求LCA的Tarjan算法中,我们利用并差集和DFS序实现,实际上在用并差集维护的时候,可以同时维护出到当前子树根的树链上的最大/次大权边。其实如果有比较深刻的体会的话,不难实现。

第二种算法(TLE)

在实现第二步的时候,使用倍增思想。

Fp[i][j]表示i这个结点,向上2^j个父亲,是谁。

FL[i][j][0..1]表示i这个结点,到向上2^j个父亲这条树链上,最大值和次大值分别是多少。

我们定义根的结点为其本身,那么就可以类似RMQ地求出这两个数组。

求他的复杂度为O(n lg n)。

然后每次询问(x,y)的时候,我们只要知道Lca(x,y),然后利用2^k步长的类似爬山的走法。就可以达到每次询问,回答的复杂度是O(n lg n)

第三种算法。

用树链剖分去解。。。但是第二种常数比较小的都A不了。。。这个就不用看了= =

【其它】

泪流满面,这么多天了,终于AC。

另外我的C++代码是算法二的,提交显示TLE,但利用批处理经过随机大量大小数据,答案与AC程序是一致的。。。

然后我之所以用Pascal,是因为C++可能要爆栈。。。所以要手写栈。

而Pascal能用编译开关调栈~= =

【CODE】【Pascal】【算法一】【AC】

{$M 10000000}
{$inline on}
const
inf=’input.txt’;
ouf=’output.txt’;
max_num=1000000000;

type
gtp=record
        y,w,zz,next:longint;
      end;
arr=array [0..1] of longint;
node=record
         x,y,w:longint;
         res:arr;
         used:boolean;
       end;

var
n,m,e,qe,lca_e:longint;
mstw:int64;
g:array [0..205555] of gtp;
qg,lca_g:array [0..605555] of gtp;
data:array [1..300000] of node;
Q,v,f,ls,qls,lca_ls:array [1..100000] of longint;
d:array [1..100000] of arr;

procedure init;
var
i:longint;
begin
e:=1; qe:=1;
read(n,m);
for i:=1 to m do
    with data[i] do
      begin
        read(x,y,w);
        used:=false;
        res[0]:=-max_num;
        res[1]:=-max_num;
      end;
for i:=1 to n do
    begin
      d[i,0]:=-max_num;
      d[i,1]:=-max_num;
    end;
end;

procedure sort(l,r:longint);
var
i,j,mid:longint;
tmp:node;
begin
if l>=r then exit;
mid:=data[(l+r) div 2].w;
i:=l; j:=r;
repeat
    while data[i].w    while data[j].w>mid do dec(j);
    if i<=j then
      begin
        tmp:=data[i]; data[i]:=data[j]; data[j]:=tmp;
        inc(i); dec(j);
      end;
until i>j;
sort(l,j);
sort(i,r);
end;

procedure addedge(x,y,w:longint);
begin
inc(e);
g[e].y:=y; g[e].next:=ls[x]; ls[x]:=e; g[e].w:=w;
end;

function gf(k:longint):longint;
begin
if f[k]=k then exit(k);
f[k]:=gf(f[k]);
exit(f[k]);
end;

procedure MST;
var
i,times:longint;
begin
times:=0;
for i:=1 to n do f[i]:=i;
for i:=1 to m do
    with data[i] do
      if gf(x)<>gf(y) then
        begin
          f[f[x]]:=f[y];
          used:=true;
          addedge(x,y,w);
          addedge(y,x,w);
          inc(MSTw,w);
          inc(times);
        end;
i:=4;
end;

procedure addq(x,y:longint);
begin
inc(qe);
qg[qe].y:=y; qg[qe].next:=qls[x]; qls[x]:=qe;
end;

procedure build;
var
i,j:longint;
begin
for i:=1 to m do
    with data[i] do
      begin
        addq(x,y);
        qg[qe].zz:=i;
        addq(y,x);
        qg[qe].zz:=i;
      end;
end;

procedure Add_Lca_Link(p,y:longint); inline;
begin
inc(lca_e);
lca_g[lca_e].y:=y;
lca_g[lca_e].next:=lca_ls[p];
lca_ls[p]:=lca_e;
end;

procedure push(var res:arr;w:longint); inline;
begin
if w=res[0] then exit;
if w>res[0] then
    begin
      res[1]:=res[0];
      res[0]:=w;
      exit;
    end;
if w>res[1] then res[1]:=w;
end;

procedure union(k:longint);
var
i,root,tmp,Qt:longint;
res:arr;
begin
i:=k;
Qt:=0;
res[0]:=-max_num;
res[1]:=-max_num;
while f[i]<>i do
    begin
      inc(Qt);
      Q[Qt]:=i;
      i:=f[i];
    end;
inc(Qt);
Q[Qt]:=i;
for i:=Qt downto 1 do
    begin
      push(d[Q[i]],res[0]);
      push(d[Q[i]],res[1]);
      push(res,d[Q[i]][0]);
      push(res,d[Q[i]][1]);
      f[Q[i]]:=Q[Qt];
    end;
end;

procedure dfs(p,fa,w:longint);
var
t:longint;
begin
t:=ls[p];
while t>0 do
    begin
      if g[t].y<>fa then
        dfs(g[t].y,p,g[t].w);
      t:=g[t].next;
    end;

t:=qls[p];
while t>0 do
    with qg[t] do
      begin
        if v[y]=1 then
          begin
            union(y);
            Add_Lca_Link(f[y],zz);
          end;
        t:=next;
      end;

t:=lca_ls[p];
while t>0 do
    with lca_g[t] do
      begin
        union(data[y].x); union(data[y].y);
        push(data[y].res,d[data[y].x,0]);
        push(data[y].res,d[data[y].x,1]);
        push(data[y].res,d[data[y].y,0]);
        push(data[y].res,d[data[y].y,1]);
        t:=next;
      end;

f[p]:=fa;
push(d[p],w);
v[p]:=1;
end;

procedure Tarjan;
var
i,j:longint;
begin
for i:=1 to n do f[i]:=i;
dfs(1,1,-max_num);
end;

function min(x,y:int64):int64;
begin
if x         else min:=y;
end;

procedure solve;
var
i:longint;
ans:int64;
begin
ans:=int64(maxlongint)*int64(maxlongint);
for i:=1 to m do
    if not data[i].used then
      begin
        if data[i].res[0]=-max_num then data[i].res[0]:=0;
        if data[i].res[0]<>data[i].w then
          ans:=min(ans,MSTw-data[i].res[0]+data[i].w)
        else if data[i].res[1]<>-max_num then
          ans:=min(ans,MSTw-data[i].res[1]+data[i].w);
      end;
writeln(ans);
end;

begin
init;
sort(1,m);
MST;
build;
Tarjan;
solve;
end.

【CODE】【C++】【算法二(倍增)】【TLE】

#include #define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
const int N=100005;
const int E=300005;
const int INF=1000000000;
const int LgN=20;
typedef __int64 lld;
struct edge{int x,y,w,next;}g[N*2];
int n,m,e,Qt;
lld MSTw;
int ls[N],F[N],FL[N][LgN][2],Fp[N][LgN],List[N],depth[N],fa[N],QL[N*2],R[N],LCA[N*2][LgN];
int Lg[N];
struct data{int x,y,w;bool used;}L[E];
inline int cmp(const void *A,const void *B){return ((data*)A)->w-((data*)B)->w;}

void Read(int &x){
     char ch=getchar();
    
}

inline void init(){
     scanf("%d%d",&n,&m);
     for (int i=1;i<=m;i++){
       scanf("%d%d%d",&L[i].x,&L[i].y,&L[i].w);
       L[i].used=false;
     }
}

inline void addedge(int x,int y,int w){
     g[++e].x=x; g[e].y=y; g[e].w=w; g[e].next=ls[x]; ls[x]=e;
     g[++e].x=y; g[e].y=x; g[e].w=w; g[e].next=ls[y]; ls[y]=e;
}

inline int GF(int v){
    int res,i,tmp;
    for (i=v;F[i]!=i;i=F[i]);
    res=i;
    for (i=v;F[i]!=i;tmp=F[i],F[i]=res,i=tmp);
    return res;
}

inline void MST(){
     e=1; memset(ls,0,sizeof(ls));
     MSTw=0;
     int tt=n;
     for (int i=1;i<=n;i++) F[i]=i;
     for (int i=1;i<=m;i++)
       if (GF(L[i].x)!=GF(L[i].y)){
         L[i].used=true;
         addedge(L[i].x,L[i].y,L[i].w);
         F[F[L[i].x]]=F[L[i].y];
         MSTw+=L[i].w;
         tt–;
         if (tt==1) break;
       }
     return;
}

inline void bfs(){
     fa[1]=0;
     int head=0,tail=1,x,y;
     List[1]=1; depth[1]=1;
     while (head!=tail){
           head++;
           for (int t=ls[List[head]];t;t=g[t].next){
               x=g[t].x; y=g[t].y;
               if (t!=(fa[x]^1)){
                 List[++tail]=y;
                 fa[y]=t;
                 depth[y]=depth[x]+1;
               }
           }
     }
}

int stack,t[N],v[N];
inline void Hand_Write_Dfs(){
     int i,y;
     for (i=1;i<=n;i++) t[i]=ls[i];
     List[1]=stack=v[1]=R[1]=Qt=QL[1]=1;
     while (stack){
          if (!t[List[stack]])
            stack–;
          else{
            int &tt=t[List[stack]];
            if (tt!=ls[List[stack]]) QL[++Qt]=List[stack];
            y=g[tt].y;
            tt=g[tt].next;
            if (!v[y]){
              List[++stack]=y;
              v[y]=1;
              QL[++Qt]=y;
              R[y]=Qt;
            }
          }
     }
}

inline void Make_LCA(){
     int i,k,s;
     for (i=1;i<=Qt;i++) LCA[i][0]=QL[i];
     for (k=1;1<       s=1<<(k-1);
       for (i=1;i+(1<         if (depth[LCA[i][k-1]]           LCA[i][k]=LCA[i][k-1];
         else
           LCA[i][k]=LCA[i+s][k-1];
     }
}

inline void Push(int *F1,int *F2){
       if (F2[0]>F1[0]) {F1[1]=F1[0]; F1[0]=F2[0];}else
       if (F2[0]>F1[1] && F2[0]!=F1[0]) F1[1]=F2[0];
       if (F2[1]>F1[0]) {F1[1]=F1[0]; F1[0]=F2[1];}else
       if (F2[1]>F1[1] && F2[1]!=F1[0]) F1[1]=F2[1];
}

inline void Make_Fa(){
     g[0].x=1; g[0].y=1; g[0].w=0;
     g[1].x=1; g[1].y=1; g[0].w=0;
     int i,k,s;
     for (i=1;i<=n;i++){
         FL[i][0][0]=g[fa[i]].w;
         FL[i][0][1]=-INF;
         Fp[i][0]=g[fa[i]].x;
     }
     for (k=1;1<       for (i=1;i<=n;i++){
           Fp[i][k]=Fp[Fp[i][k-1]][k-1];
           FL[i][k][0]=-INF;
           FL[i][k][1]=-INF;
           Push(FL[i][k],FL[i][k-1]);
           Push(FL[i][k],FL[Fp[i][k-1]][k-1]);
       }
}

inline void Make_Log(){
     Lg[1]=0;
     for (int i=2;i<=Qt;i++)
       if (1 << (Lg[i-1]+1)==i)
         Lg[i]=Lg[i-1]+1;
       else
         Lg[i]=Lg[i-1];
}

inline int Get_Lca(int l,int r){
    if (l>r){l^=r;r^=l;l^=r;}
    int k=Lg[r-l+1];
    if (depth[LCA[l][k]]      return LCA[l][k];
    else
      return LCA[r-(1<}

int res[2];
inline void Get_Max(int x,int y){
     int i,k=Lg[n];
     i=y;
     while (i!=x){
           while (depth[Fp[i][k]]           Push(res,FL[i][k]);
           i=Fp[i][k];
     }
}

inline void solve(){
     int i,Lca;
     lld ans=(lld)(1) << 60;
     for (i=1;i<=m;i++)
       if (!L[i].used){
         Lca=Get_Lca(R[L[i].x],R[L[i].y]);
         res[0]=-INF;
         res[1]=-INF;
         Get_Max(Lca,L[i].x);
         Get_Max(Lca,L[i].y);
         if (res[0]!=L[i].w)
           ans=min(ans,MSTw-res[0]+L[i].w);
         else if (res[1]!=-INF)
           ans=min(ans,MSTw-res[1]+L[i].w);
       }
     printf("%I64dn",ans);
}

int main(){
    init();
    qsort(L+1,m,sizeof(data),cmp);
    MST();
    bfs();
    Hand_Write_Dfs();
    Make_LCA();
    Make_Fa();
    Make_Log();
    solve();
    return 0;
}

加入对话

9条评论

  1. 回复lilymona:有几种可能。。。1、爆int,要int64。而你的写了%lld之流。。。2、DFS时爆栈了。。。。你本机可能(系统/编译器)栈比较大。3、他该数据了。。。。。。。。。剩下的就不明真相了

留下评论

回复 ad饕饕不绝 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注