题目大意:给定一张无向图,每个点有边权,给每个联通块大小一个喜爱度,求一个最小的区间,使保留这个区间内的所有边权的边时喜爱度之和最大
n<=1000,m<=5000
脑残没法治系列……
如果暴力枚举区间并每次计算喜爱度,时间复杂度为O(nm^2),超时
固定一个左端点,将右端点右移,每次用并查集加边并维护喜爱度之和,时间复杂度O(m^2)
然后这题就做完了= =
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1010 using namespace std; struct abcd{ int x,y,f; friend istream& operator >> (istream &_,abcd &a) { scanf("%d%d%d",&a.x,&a.y,&a.f); return _; } bool operator < (const abcd &a) const { return f<a.f; } }edges[5050]; int n,m,k,ans=2147483647; int w[M]; long long sum; namespace Union_Find_Set{ int fa[M],size[M]; int Find(int x) { if(!fa[x]) fa[x]=x,size[x]=1; if(fa[x]==x) return x; return fa[x]=Find(fa[x]); } void Union(int x,int y) { x=Find(x);y=Find(y); if(x==y) return ; if(size[x]>size[y]) swap(x,y); sum-=w[size[x]]; sum-=w[size[y]]; fa[x]=y;size[y]+=size[x]; sum+=w[size[y]]; } } int main() { using namespace Union_Find_Set; int i,j; cin>>n>>m>>k; for(i=1;i<=n;i++) scanf("%d",&w[i]); for(i=1;i<=m;i++) cin>>edges[i]; sort(edges+1,edges+m+1); for(i=1;i<=m;i++) if(i==1||edges[i].f!=edges[i-1].f) { sum=(long long)n*w[1]; memset(fa,0,sizeof fa); for(j=i;j<=m;j++) { Union(edges[j].x,edges[j].y); if(j==m||edges[j].f!=edges[j+1].f) if(sum>=k) { ans=min(ans,edges[j].f-edges[i].f); break; } } } if(ans==2147483647) cout<<"T_T"<<endl; else cout<<ans<<endl; return 0; }
原文地址:http://blog.csdn.net/popoqqq/article/details/43957283