并查集——codevs 1188City战争

xiaoxiao2021-02-28  96

http://codevs.cn/problem/1188/ 我靠我不会; fop_zz教我了半天我才会的; 首先n*n的暴力就是每条线段从两个点dfs; 然后把两个点的值乘起来*2; 这就是一条的值了; 我们在考虑权值不同的情况; 我们只要把边从小到大排序然后用并查集维护就好了; 但是如果边权有相同的情况就不好搞了;

有一个想法; 就是我们同一个权值的边一起加; 对于一条边,加之前其一段的点数是a,加之后是总共点数b; 那么值就是(b-a)*a*2; 这就有问题了,我们并查集不可以存点数了; 因为并查集在不断变化; 那我们只好把点数存在点上了; 这个时候我们要先搞一个dfs树; 记录每个节点的深度; 而并查集维护的就是这个联通快的点数放在哪里; 其实全放在联通快深度最高点; 我们合并两个并查集的时候,就要把低节点合并到高节点去; 比如x-y这一线段 x深度浅 那么get(y)一定是y 我们要把 fa[y]=get(x) 并且把点数合并过去; 于是y~get(x)的点的点数全要加x的点数; 因为我们要计算答案的; 仅仅把get(x)的权值加上y是不够的;

#include<bits/stdc++.h> #define Ll long long using namespace std; const int N=1e5+5; struct cs{int v,to,nxt;}a[N*2]; struct in{int x,y,z,num;}I[N]; struct dian{int deep,fa,size;}d[N]; int fa[N]; int head[N],ll; int an[N],top; Ll ans; int n,m,l,r,x,y,z; void init(int x,int y,int z){ a[++ll].to=y; a[ll].v=z; a[ll].nxt=head[x]; head[x]=ll; } void dfs(int x,int y,int z){ d[x].deep=z; d[x].fa=y; d[x].size=1; fa[x]=x; for(int k=head[x];k;k=a[k].nxt) if(a[k].to!=y)dfs(a[k].to,x,z+1); } bool cmp(in a,in b){return a.z<b.z;} int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);} void insert(int x,int y){ int yy=get(y); fa[x]=yy; for(int k=d[x].fa;k!=yy;k=d[k].fa)d[k].size+=d[x].size; d[yy].size+=d[x].size; } int main() { freopen("City.in","r",stdin); freopen("City.out","w",stdout); scanf("%d",&n);n--; for(int i=1;i<=n;i++){ scanf("%d%d%d",&x,&y,&z); I[i].x=x; I[i].y=y; I[i].z=z; I[i].num=i; init(x,y,z);init(y,x,z); } dfs(1,-1,1); sort(I+1,I+n+1,cmp); l=1;r=1; while(l<=n){ while(r+1<=n&&I[r+1].z==I[r].z)r++; for(int i=l;i<=r;i++){ x=I[i].x; y=I[i].y; if(d[x].deep>d[y].deep)insert(x,y);else insert(y,x); } for(int i=l;i<=r;i++){ x=I[i].x; y=I[i].y; if(d[x].deep>d[y].deep){ y=d[get(y)].size; x=d[x].size; }else{ y=d[y].size; x=d[get(x)].size; swap(x,y); } Ll temp=(Ll)(y-x)*x; if(ans==temp)an[++top]=I[i].num; if(ans<temp)ans=temp,an[top=1]=I[i].num; } l=r+1;r=l; } sort(an+1,an+top+1); printf("%lld %d\n",ans*2,top); for(int i=1;i<=top;i++)printf("%d ",an[i]); }

其实这种写法会被卡掉; 我们搞一条链的话

for(int k=d[x].fa;k!=yy;k=d[k].fa)d[k].size+=d[x].size;

这里会萎; 但是如果我们把同权值的线段先排序; 这就好啦

转载请注明原文地址: https://www.6miu.com/read-47217.html

最新回复(0)