题目链接
点击打开链接
题目解法
首先给出 2 个结论:
- 最接近的不同颜色的点一定是相邻的点
证明:假设最接近的不同颜色的点 ( u , v ) (u,v) (u,v) 不相邻,那么 u , v u,v u,v 之间的路径中必有相邻的不同颜色点 ( u ′ , v ′ ) (u',v') (u′,v′), d i s ( u ′ , v ′ ) < d i s ( u , v ) dis(u',v')<dis(u,v) dis(u′,v′)<dis(u,v),矛盾 - 最接近的不同颜色的点一定在任意一个最小生成树上
证明:假设最接近的不同颜色的点 ( u , v ) (u,v) (u,v) 不在最小生成树上(可以是任意一棵)
根据 MST 的性质, u , v u,v u,v 之间的路径上的每一条边的 L e n t h < = l e n t h ( u , v ) Lenth<=lenth(u,v) Lenth<=lenth(u,v)
因为 u , v u,v u,v 颜色不同,那么 u , v u,v u,v 的路径上必有相邻的不同颜色点,长度一定 ≤ l e n t h ( u , v ) \le lenth(u,v) ≤lenth(u,v)
考虑建出一棵 MST
对于每个结点维护一棵线段树,在儿子的颜色信息上维护最小距离
同时在叶节点处用 m u l t i s e t multiset multiset 维护当前颜色的所有距离即可
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include <bits/stdc++.h>
using namespace std;
const int N(200100),inf(0x3f3f3f3f);
struct LINES{int x,y,z;
}lines[N];
int n,m,k,q,fa[N],col[N],FA[N],W[N],mndis[N];
int e[N<<1],w[N<<1],ne[N<<1],h[N],idx;
int tot,root[N],seg[N*38],lc[N*38],rc[N*38];
int tot2,dy[N*38];
bool leaf[N];
multiset<int> se[N<<1],ans;
inline int read(){int FF=0,RR=1;char ch=getchar();for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;return FF*RR;
}
bool cmp(const LINES &x,const LINES &y){ return x.z<y.z;}
int get_father(int x){ return x==fa[x]?x:fa[x]=get_father(fa[x]);}
int insert(int p,int l,int r,int pos,int c){if(!p) p=++idx;if(l==r){if(!dy[p]) dy[p]=++tot2;se[dy[p]].insert(c);seg[p]=min(seg[p],c);return p;}int mid=(l+r)>>1;if(mid>=pos) lc[p]=insert(lc[p],l,mid,pos,c);else rc[p]=insert(rc[p],mid+1,r,pos,c);seg[p]=min(seg[lc[p]],seg[rc[p]]);return p;
}
void dfs(int u,int fa){leaf[u]=1,FA[u]=fa;for(int i=h[u];~i;i=ne[i]){int v=e[i];if(v!=fa) leaf[u]=0,dfs(v,u),W[v]=w[i],root[u]=insert(root[u],1,n,col[v],w[i]); }
}
int query(int p,int l,int r,int L,int R){if(L>R||!p) return inf;if(L<=l&&r<=R) return seg[p];int mid=(l+r)>>1;if(mid>=L&&mid<R) return min(query(lc[p],l,mid,L,R),query(rc[p],mid+1,r,L,R));if(mid>=L) return query(lc[p],l,mid,L,R);return query(rc[p],mid+1,r,L,R);
}
void cover(int p,int l,int r,int pos,int w){if(l==r){se[dy[p]].erase(se[dy[p]].find(w));if(se[dy[p]].empty()) seg[p]=inf;else seg[p]=*se[dy[p]].begin();return;}int mid=(l+r)>>1;if(mid>=pos) cover(lc[p],l,mid,pos,w);else cover(rc[p],mid+1,r,pos,w);seg[p]=min(seg[lc[p]],seg[rc[p]]);
}
void add(int a,int b,int c){ e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;}
int main(){ n=read(),m=read(),k=read(),q=read();for(int i=1,x,y,z;i<=m;i++) x=read(),y=read(),z=read(),lines[i]={x,y,z};sort(lines+1,lines+m+1,cmp);for(int i=1;i<=n;i++) fa[i]=i;memset(h,-1,sizeof(h));for(int i=1,j=0;i<=m;i++){if(j==n-1) break;int fa0=get_father(lines[i].x),fa1=get_father(lines[i].y);if(fa0!=fa1){fa[fa0]=fa1,j++;add(lines[i].x,lines[i].y,lines[i].z),add(lines[i].y,lines[i].x,lines[i].z);}}memset(seg,0x3f,sizeof(seg));for(int i=1;i<=n;i++) col[i]=read();dfs(1,-1);for(int i=1;i<=n;i++) if(!leaf[i]) mndis[i]=min(query(root[i],1,n,1,col[i]-1),query(root[i],1,n,col[i]+1,n)),ans.insert(mndis[i]);while(q--){int x=read(),val=read();if(!leaf[x]){ans.erase(ans.find(mndis[x]));mndis[x]=min(query(root[x],1,n,1,val-1),query(root[x],1,n,val+1,n));ans.insert(mndis[x]);}if(x!=1){ans.erase(ans.find(mndis[FA[x]]));cover(root[FA[x]],1,n,col[x],W[x]);insert(root[FA[x]],1,n,val,W[x]);mndis[FA[x]]=min(query(root[FA[x]],1,n,1,col[FA[x]]-1),query(root[FA[x]],1,n,col[FA[x]]+1,n));ans.insert(mndis[FA[x]]);}col[x]=val;printf("%d\n",*ans.begin());}return 0;
}