[并查集]JZOJ 3301 家族
由于写这篇博文的时候OJ炸掉啦,所以只给出题目大意
告诉你d[i]表示大小为i的联通块的权值,要求问需要删去所有权值为[l..r]的边,问使联通块权值之和>=k的最小区间(长度)
分析
比赛的时候自己脑抽了,没发现没二分性,不能二分……
然后不能二分以后还没根据数据规模推断,其实m^2logn暴力就行了……扎心
然后提到联通块必想到并查集,随便鼓捣一下就过了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <algorithm> #include <memory.h> using namespace std; typedef long long ll; const int N=1e3+10; struct Edge { int u,v; ll w; friend bool operator < (Edge a,Edge b) { return a.w<b.w; } }g[5*N]; int n,m; ll k,a[N],ans=2147483647; int f[N],sz[N]; int Get_F(int x) {return f[x]==x?x:f[x]=Get_F(f[x]);} int main() { scanf("%d%d%lld",&n,&m,&k); for (int i=1;i<=n;i++) scanf("%lld",&a[i]); for (int i=1;i<=m;i++) scanf("%d%d%lld",&g[i].u,&g[i].v,&g[i].w); sort(g+1,g+m+1); for (int i=1;i<=m;i++) { for (int j=1;j<=n;j++) f[j]=j,sz[j]=1; ll cnt=n*a[1]; for (int j=i;j<=m;j++) { if (ans<=g[j].w-g[i].w) break; int x=Get_F(g[j].u),y=Get_F(g[j].v); if (x!=y) { f[y]=x; cnt=cnt-a[sz[x]]-a[sz[y]]; sz[x]+=sz[y]; cnt+=a[sz[x]]; } if (cnt>=k) { ans=min(ans,g[j].w-g[i].w); break; } } } if (ans==2147483647) printf("T_T"); else printf("%lld",ans); }
在日渐沉没的世界里,我发现了你。