P1967 货车运输

wenge

2020-10-07 21:20:15

Personal

原题要处理连通块,但是建一个超级源点0,到其他边的边权全部设为-1,就可以避免连通块的问题,并且倍增LCA询问还不需要特判 倍增解法: ```cpp //#pragma GCC optimize(2) #include <bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back #define clr(a,b) memset(a,b,sizeof(a)) ll n,m,q,ans; const ll inf=-1; struct edge{ ll u,v,w; edge(){} edge(ll _u,ll _v,ll _w):u(_u),v(_v),w(_w){} }e[60005]; int cmp_edge(edge x,edge y){ return x.w>y.w; } ll p[10005]; ll find(ll x){ if(p[x]==x)return x; return p[x]=find(p[x]); } ll merge(ll x,ll y){ x=find(x),y=find(y); if(x!=y)p[x]=y; } vector<ll> F[10005],G[10005]; ll pow2[20]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384}; ll fa[10005][20],mx[10005][20],dep[10005]; void dfs1(ll x,ll z){ for(int i=0;i<F[x].size();i++){ ll y=F[x][i],w=G[x][i]; if(y==z)continue; fa[y][0]=x,mx[y][0]=w,dep[y]=dep[x]+1; dfs1(y,x); } } ll query(ll x,ll y){ if(dep[x]<dep[y])swap(x,y); ll delta=dep[x]-dep[y]; ll res=99999999; for(int i=14;i>=0;i--){ if(pow2[i]<=delta){ res=min(res,mx[x][i]); x=fa[x][i]; delta-=pow2[i]; } } if(x==y)return res; for(int i=14;i>=0;i--){ if(dep[x]-pow2[i]>=0&&fa[x][i]!=fa[y][i]){ res=min(res,mx[x][i]); res=min(res,mx[y][i]); x=fa[x][i]; y=fa[y][i]; } } res=min(res,mx[x][0]); res=min(res,mx[y][0]); return res; } int main(){ //freopen("P1429_6.in","r",stdin); //freopen("match.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0); //input cin>>n>>m; for(int i=1;i<=m;i++){ cin>>e[i].u>>e[i].v>>e[i].w; } for(int i=1;i<=n;i++){ e[m+i].u=0,e[m+i].v=i,e[m+i].w=inf; } m+=n; //mst sort(e+1,e+m+1,cmp_edge); { for(int i=0;i<=n;i++)p[i]=i; ll t=0; for(int i=1;i<=m;i++){ ll u=e[i].u,v=e[i].v,w=e[i].w; if(find(u)!=find(v)){ merge(u,v); t++; F[u].pb(v); F[v].pb(u); G[u].pb(w); G[v].pb(w); } if(t==n)break; } } //graph dep[0]=0; dfs1(0,-1); for(int i=1;i<=14;i++){ for(int j=0;j<=n;j++){ fa[j][i]=fa[fa[j][i-1]][i-1]; mx[j][i]=min(mx[j][i-1],mx[fa[j][i-1]][i-1]); } } //query cin>>q; while(q--){ ll u,v; cin>>u>>v; cout<<query(u,v)<<"\n"; } return 0; } ```