WOJ#2723 簡單題 題解
阿新 • • 發佈:2021-08-19
真nm簡單。。
演算法1:
發現其實所有的經過的邊都是最小生成樹上面的邊,跑出最小生成樹在上面求LCA即可。
演算法2:
考慮從小到列舉每一個加入的邊,直到組成最小生成樹,沒加一條邊就判斷所有的詢問是否連通。
然後我們發現這個演算法有點卡,於是我們可以進行優化:
1、開一個beg,beg前的全部列舉過就不用枚舉了。
2、記錄每一個點被加入最小生成樹的時間,然後詢問按照這個時間從小到大排序,每當找到一個詢問中有點不在最小生成樹裡面就可以退出列舉。
然後就可以過了awa
#include<bits/stdc++.h> using namespace std; const int M=100005; const int N=10005; int n,m,cnt=0,k=0,first[M<<1],nxt[M<<1],fa[N],f[N][25],dis[N][25],dep[N]; struct node{ int u,v; int w; }a[M<<1],e[M<<1]; int cmp(node A,node B){ return A.w<B.w; } void add(int u,int v,int w){ e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w; nxt[cnt]=first[u];first[u]=cnt; } int find(int x){ if(x==fa[x]) return x; else return fa[x]=find(fa[x]); } void unionn(int x,int y){ fa[x]=y; } void kruskal(){ for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ int f1=find(a[i].u); int f2=find(a[i].v); if(f1!=f2){ unionn(f1,f2); add(a[i].u,a[i].v,a[i].w); add(a[i].v,a[i].u,a[i].w); k++; } if(k==n-1) break; } } void dfs(int u){ for(int i=1;(1<<i)<=dep[u];i++){ f[u][i]=f[f[u][i-1]][i-1]; dis[u][i]=max(dis[f[u][i-1]][i-1],dis[u][i-1]); } for(int i=first[u];i;i=nxt[i]){ int v=e[i].v; if(!dep[v]){ dep[v]=dep[u]+1; f[v][0]=u; dis[v][0]=e[i].w; dfs(v); } } } int LCA(int a,int b){ if(dep[a]<dep[b]) swap(a,b); int t=dep[a]-dep[b]; for(int i=0;(1<<i)<=t;i++) if(t&(1<<i)) a=f[a][i]; if(a==b) return a; for(int j=19;j>=0;j--){ if(f[a][j]!=f[b][j]) a=f[a][j],b=f[b][j]; } return f[a][0]; } int query(int u,int v){ int t=dep[u]-dep[v],ans=0; for(int i=0;(1<<i)<=t;i++) if(t&(1<<i)){ ans=max(ans,dis[u][i]); u=f[u][i]; } return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); } sort(a+1,a+1+m,cmp); kruskal(); dep[1]=1; dfs(1); int q; scanf("%d",&q); for(int i=1;i<=q;i++){ int u,v; scanf("%d%d",&u,&v); int mid=LCA(u,v); printf("%d\n",max(query(u,mid),query(v,mid))); } return 0; }
演算法1如上
還有演算法2:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define orz cout<<"lyakioi!!!!!!!!!!!!!!!!!"<<endl inline int r(){int s=0,k=1;char c=getchar();while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}while(isdigit(c)){s=s*10+c-'0';c=getchar();}return s*k;} int n,m,q,fa[1000001],beg,times,b[1000001],used[1000001]; struct node { int from,to,dis; }a[1000001]; struct ask { int from,to,bh,ans; }t[1000001]; bool cmp(node x,node y) { return x.dis<y.dis; } bool pmc(ask x,ask y) { return max(b[x.from],b[x.to])<max(b[y.from],b[y.to]); } bool mcp(ask x,ask y) { return x.bh<y.bh; } int father(int x) { if(fa[x]!=x)fa[x]=father(fa[x]); return fa[x]; } int main() { beg=1; n=r();m=r(); memset(b,0x3f,sizeof(b)); for(int i=1;i<=m;i++) { a[i].from=r(); a[i].to=r(); a[i].dis=r(); } q=r(); for(int i=1;i<=q;i++) { t[i].from=r(); t[i].to=r(); t[i].bh=i; } sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++) { int x=a[i].from,y=a[i].to; if((b[x]>1e9)||(b[y]>1e9)) { times++; b[x]=min(b[x],times); b[y]=min(b[y],times); } } sort(t+1,t+q+1,pmc); // for(int i=1;i<=) for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++) { int x=a[i].from,y=a[i].to; used[x]=used[y]=1; int fax=father(x),fay=father(y); if(fax!=fay) { fa[fax]=fay; for(int j=beg;j<=q;j++) { if(t[j].ans)continue; x=t[j].from,y=t[j].to; if(!used[x]||!used[y])break; fax=father(x),fay=father(y); if(fax==fay)t[j].ans=a[i].dis; while(t[beg].ans)beg++; } } } sort(t+1,t+q+1,mcp); for(int i=1;i<=q;i++)cout<<t[i].ans<<endl; }