标签:its cond 直接 最小生成树 差分 f11 不用 答案 hide
先求出任意一棵最小生成树,然后对边分类讨论
1.非树边,答案即最小生成树的环上的最长边
2.树边,反过来考虑,相当于对于每一个点对那条路经打上标记,取min
对于1直接用倍增维护即可,对于2可以用树链剖分/差分+启发式合并但都需要两个log,所以有一种很神奇的做法
考虑从小到大枚举非树边,然后暴力修改,容易发现修改过的边就不用修改了,因此复杂度是o(m),问题是如何快速找到没有被修改过的边,可以使用并查集将修改过的边缩起来然后快速往上爬即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define mid (l+r>>1) 5 struct ji{ 6 int x,y,z,id; 7 }e[N*10]; 8 struct ji2{ 9 int nex,to,len,id; 10 }edge[N<<1]; 11 int E,n,m,x,y,head[N],sh[N],ff[N],up[N],vis[N*10],ans[N*10],f[N][21],mx[N][21]; 12 bool cmp(ji x,ji y){ 13 return x.z<y.z; 14 } 15 int find(int k){ 16 if (k==ff[k])return k; 17 return ff[k]=find(ff[k]); 18 } 19 void add(int x,int y,int z,int id){ 20 edge[E].nex=head[x]; 21 edge[E].to=y; 22 edge[E].len=z; 23 edge[E].id=id; 24 head[x]=E++; 25 } 26 void dfs(int k,int fa,int id,int s){ 27 sh[k]=s; 28 up[k]=id; 29 f[k][0]=fa; 30 for(int i=1;i<=20;i++){ 31 f[k][i]=f[f[k][i-1]][i-1]; 32 mx[k][i]=max(mx[k][i-1],mx[f[k][i-1]][i-1]); 33 } 34 for(int i=head[k];i!=-1;i=edge[i].nex) 35 if (edge[i].to!=fa){ 36 mx[edge[i].to][0]=edge[i].len; 37 dfs(edge[i].to,k,edge[i].id,s+1); 38 } 39 } 40 pair<int,int> lca(int x,int y){ 41 if (sh[x]<sh[y])swap(x,y); 42 int ans=0; 43 for(int i=20;i>=0;i--) 44 if (sh[f[x][i]]>=sh[y]){ 45 ans=max(ans,mx[x][i]); 46 x=f[x][i]; 47 } 48 if (x==y)return make_pair(x,ans); 49 for(int i=20;i>=0;i--) 50 if (f[x][i]!=f[y][i]){ 51 ans=max(ans,max(mx[x][i],mx[y][i])); 52 x=f[x][i]; 53 y=f[y][i]; 54 } 55 return make_pair(f[x][0],max(ans,max(mx[x][0],mx[y][0]))); 56 } 57 int main(){ 58 scanf("%d%d",&n,&m); 59 for(int i=1;i<=m;i++){ 60 scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); 61 e[i].id=i; 62 } 63 sort(e+1,e+m+1,cmp); 64 memset(head,-1,sizeof(head)); 65 for(int i=1;i<=n;i++)ff[i]=i; 66 for(int i=1;i<=m;i++){ 67 x=find(e[i].x); 68 y=find(e[i].y); 69 if (x!=y){ 70 ff[x]=y; 71 add(e[i].x,e[i].y,e[i].z,e[i].id); 72 add(e[i].y,e[i].x,e[i].z,e[i].id); 73 vis[i]=1; 74 } 75 } 76 dfs(1,0,0,0); 77 for(int i=1;i<=m;i++)ans[i]=1000000000; 78 for(int i=1;i<=n;i++)ff[i]=i; 79 for(int i=1;i<=m;i++) 80 if (!vis[i]){ 81 x=lca(e[i].x,e[i].y).first; 82 ans[e[i].id]=lca(e[i].x,e[i].y).second; 83 while (find(e[i].x)!=find(x)){ 84 e[i].x=find(e[i].x); 85 ans[up[e[i].x]]=e[i].z; 86 if (find(e[i].x)!=find(f[e[i].x][0]))ff[find(e[i].x)]=find(f[e[i].x][0]); 87 } 88 while (find(e[i].y)!=find(x)){ 89 e[i].y=find(e[i].y); 90 ans[up[e[i].y]]=e[i].z; 91 if (find(e[i].y)!=find(f[e[i].y][0]))ff[find(e[i].y)]=find(f[e[i].y][0]); 92 } 93 } 94 for(int i=1;i<=m;i++)printf("%d\n",ans[i]); 95 }
标签:its cond 直接 最小生成树 差分 f11 不用 答案 hide
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11842540.html