今天說是要練習LCA結果找了道題看着題解打完了,如此慚愧,Lca還得好好理解啊,感覺在最大生成樹上做有點異樣,可能還是不是很理解吧,在noip前一定要再把這道題再a一遍,好題啊。

這是2013noipt3的題,難度適中,比以往的簡單沒讓人想不出來思路雖然我第一遍看也沒想起來但是題解易懂,是我這種低級選手能做的題,所以今天下午選擇做這道題,看着題解打了3h終於大功告成,一部分是抄的真心不會啊lca,昨天剛學還是打不下了。打完代碼后按了下F7,嗯,100+errors真的很難受,代碼能力過差,然后調試調了30多分鍾,各種i打成j各種w打成fa,真的是醉了,按照湯神的話來說就是打代碼的時候你在想什么,湯神看代碼很准的基本上沒什么錯誤orztql,於是乎和上一遍lca並不一樣的不在於求最大生成樹(這個非常好打)而是定根節點,要不這個最大的生成樹可以看成一條線,如果不定根節點的話,誰知道你的最近公共祖先是誰,然后就是倍數的問題二進制的拆分,直接從20開始不必log(n)/log(i);因為n不可能超過2的20次方,盡管這樣浪費一點時間,但是無關緊要,還有就是一點不是很理解的就是lca的初始化不是很懂啊,盡管明白那是個狀態轉移,但是呢打起來的時候還是迷茫,不理解內層因為i是從20開始的,於是乎到達很大的i的時候那時的祖先都是已經達到的祖先了這些都其實沒什么用,還是寫篇博客更好,又加深了理解,很棒呢!
下面是代碼了接近150行代碼=-= 好累。
#include<iostream> #include<cmath> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iomanip> #include<algorithm> #include<ctime> #include<map> #include<vector> #include<stack> #define inf 10000007 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=50002; struct bwy { int x,y,dis; }s[maxn]; int e[maxn],nex[maxn],lin[maxn],ver[maxn],len; int f[maxn],fa[maxn][30],w[maxn][30],depth[maxn],vis[maxn]; void add(int x,int y,int z) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; e[len]=z; } int n,m,k; int my(bwy x,bwy y) { return x.dis>y.dis; } int getfather(int x) { if(x==f[x]) return x; return f[x]=getfather(f[x]); } void kruskal() { for(int i=1;i<=n;i++) f[i]=i; sort(s+1,s+1+m,my); for(int i=1;i<=m;i++) { int xx=getfather(s[i].x); int yy=getfather(s[i].y); if(xx!=yy) { f[xx]=yy; add(s[i].x,s[i].y,s[i].dis); add(s[i].y,s[i].x,s[i].dis); } } } void dfs(int num) { vis[num]=1; for(int i=lin[num];i!=0;i=nex[i]) { int tn=ver[i]; if(vis[tn]==1) continue; depth[tn]=depth[num]+1; fa[tn][0]=num; w[tn][0]=e[i]; dfs(tn); } return; } int lca(int x,int y) { if(getfather(x)!=getfather(y)) return -1; int ans=inf; if(depth[x]>depth[y]) swap(x,y); for(int i=20;i>=0;i--) { if(depth[fa[y][i]]>=depth[x]) { ans=min(ans,w[y][i]); y=fa[y][i]; } } if(x==y)return ans; for(int i=20;i>=0;i--) { if(fa[x][i]!=fa[y][i]) { ans=min(ans,min(w[x][i],w[y][i])); x=fa[x][i],y=fa[y][i]; } } ans=min(ans,min(w[x][0],w[y][0])); return ans; } int main() { //freopen("1.in","r",stdin); n=read();m=read(); for(int i=1;i<=m;i++) { s[i].x=read();s[i].y=read();s[i].dis=read(); } kruskal(); for(int i=1;i<=n;i++) { if(vis[i]!=1) { depth[i]=1; dfs(i); fa[i][0]=i; w[i][0]=inf; } } for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) { fa[j][i]=fa[fa[j][i-1]][i-1]; w[j][i]=min(w[j][i-1],w[fa[j][i-1]][i-1]); } k=read(); for(int i=1;i<=k;i++) { int x,y; x=read();y=read(); cout<<lca(x,y)<<endl; } return 0; }
一天又過去,希望時間沒白費。
蕭瑟蘭成看老去,為怕多情,不作憐花句。
