[并查集]JZOJ 3301 家族

 

由于写这篇博文的时候OJ炸掉啦,所以只给出题目大意

告诉你d[i]表示大小为i的联通块的权值,要求问需要删去所有权值为[l..r]的边,问使联通块权值之和>=k的最小区间(长度)

分析

比赛的时候自己脑抽了,没发现没二分性,不能二分……

然后不能二分以后还没根据数据规模推断,其实m^2logn暴力就行了……扎心

然后提到联通块必想到并查集,随便鼓捣一下就过了

 

#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);
}
View Code

 

posted @ 2019-07-06 07:33  Vagari  阅读(148)  评论(0编辑  收藏  举报