【Codeforces】1051F. The Shortest Statement【MST+LCA+最短路】
阿新 • • 發佈:2018-12-19
F. The Shortest Statement
【題目描述】
【題解】
題目也說了,重點是m-n<=20,我們就可以先跑最小生成樹,最後剩下最多21條邊,對著44個端點(包括起點和終點)用LCA建圖,跑最短路就可以了。
程式碼如下
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN=1e5+5; typedef long long LL; struct HEAP{ int x,ID; bool operator <(const HEAP b)const{return x>b.x;} }; priority_queue<HEAP> hep; int n,m,Top,fa[MAXN],Dep[MAXN],Fa[MAXN][30],point[MAXN],Num;LL dst[MAXN],Sum[MAXN];bool vis[MAXN]; int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);} struct Edge{ int tot,lnk[MAXN],nxt[MAXN<<1],son[MAXN<<1];LL W[MAXN<<1]; void clean(){memset(lnk,0,sizeof(lnk));tot=0;} void Add(int x,int y,LL w){nxt[++tot]=lnk[x];son[tot]=y;W[tot]=w;lnk[x]=tot;} }E,S,T; struct xcw{ int x,y,w; bool operator <(const xcw b)const{return w<b.w;} }a[MAXN],b[25]; #include<cctype> int read(){ int ret=0;char ch=getchar();bool f=1; for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-'); for(; isdigit(ch);ch=getchar()) ret=(ret<<1)+(ret<<3)+ch-48; return f?ret:-ret; } void DFS(int x,int f){ Fa[x][0]=f;Dep[x]=Dep[f]+1; for(int j=E.lnk[x];j;j=E.nxt[j]) if(E.son[j]!=f) Sum[E.son[j]]=Sum[x]+E.W[j],DFS(E.son[j],x); } void INIT(){ for(int j=1;(1<<j)<=n;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1]; } int LCA(int x,int y){ if(Dep[x]<Dep[y]) swap(x,y); int Del=Dep[x]-Dep[y]; for(int i=0;(1<<i)<=Del;i++) if((1<<i)&Del) x=Fa[x][i]; if(x==y) return x; for(int i=log2(n);i>=0;i--) if(Fa[x][i]!=Fa[y][i]) x=Fa[x][i],y=Fa[y][i]; return Fa[x][0]; } void DIJ(int x){ dst[x]=0;hep.push((HEAP){0,x}); while(!hep.empty()){ HEAP Now=hep.top();hep.pop(); for(int j=S.lnk[Now.ID];j;j=S.nxt[j]) if(dst[S.son[j]]>dst[Now.ID]+S.W[j]) dst[S.son[j]]=dst[Now.ID]+S.W[j],hep.push((HEAP){dst[S.son[j]],S.son[j]}); for(int j=T.lnk[Now.ID];j;j=T.nxt[j]) if(dst[T.son[j]]>dst[Now.ID]+T.W[j]) dst[T.son[j]]=dst[Now.ID]+T.W[j],hep.push((HEAP){dst[T.son[j]],T.son[j]}); } } int main(){ // freopen("prob.in","r",stdin); // freopen("prob.out","w",stdout); n=read(),m=read(); for(int i=1;i<=m;i++) a[i]=(xcw){read(),read(),read()}; sort(a+1,a+1+m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++){ int fx=get(a[i].x),fy=get(a[i].y); if(fx==fy){b[++Top]=a[i],point[++Num]=a[i].x,point[++Num]=a[i].y;continue;} fa[fy]=fx;E.Add(a[i].x,a[i].y,a[i].w),E.Add(a[i].y,a[i].x,a[i].w); } sort(point+1,point+1+Num); Num=unique(point+1,point+1+Num)-point-1; DFS(1,0);INIT(); for(int i=1;i<=Top;i++) S.Add(b[i].x,b[i].y,b[i].w),S.Add(b[i].y,b[i].x,b[i].w); for(int i=1;i<=Num;i++) for(int j=i+1;j<=Num;j++){ int F=LCA(point[i],point[j]); S.Add(point[i],point[j],Sum[point[i]]+Sum[point[j]]-Sum[F]*2);S.Add(point[j],point[i],Sum[point[i]]+Sum[point[j]]-Sum[F]*2); } int q=read(); while(q--){ int x=read(),y=read(); int F=LCA(x,y);T.Add(y,x,Sum[y]+Sum[x]-Sum[F]*2),T.Add(x,y,Sum[y]+Sum[x]-Sum[F]*2); for(int i=1;i<=Num;i++){ F=LCA(point[i],x); T.Add(point[i],x,Sum[point[i]]+Sum[x]-Sum[F]*2),T.Add(x,point[i],Sum[point[i]]+Sum[x]-Sum[F]*2); F=LCA(point[i],y); T.Add(point[i],y,Sum[point[i]]+Sum[y]-Sum[F]*2),T.Add(y,point[i],Sum[point[i]]+Sum[y]-Sum[F]*2); } dst[x]=dst[y]=1ll<<60;vis[x]=vis[y]=0; for(int i=1;i<=Num;i++) dst[point[i]]=1ll<<60,vis[point[i]]=0; DIJ(x); printf("%lld\n",dst[y]); T.lnk[x]=T.lnk[y]=0,T.tot=0; for(int i=1;i<=Num;i++) T.lnk[point[i]]=0; } return 0; }