【kruscal】【最小生成树】【离线】洛谷 P2266 爱的距离

建图:每个点向它四周的点连边权为两点点权的差的绝对值的边。

由于有多个需要“施法”的点,所以相当于对每个这样的点,询问与它的距离在T以内的最长边的最小值,即多次询问。

最长边最小之类的,肯定是最小生成树没跑了。BUT 若是对每个点这样做的话,肯定会TLE。

所以考虑一次处理出所有询问的答案。

在并查集将两个点集连边的时候,若两个点集的点数和<T,则对这两个集内的询问点都没有影响。

若两个点集的点数和>=T,则若A(B)集原来的点数<T,则A(B)集内的询问点都符合了题意,这个最大值就是当前这条边的边权,当然kruscal是贪心的,所以这个值是最小的。

所以并查集除了维护连通性之外,还要维护某个集合的顶点数以及某个集合的询问点数。

P.S.由于NOIP用**的devc++4.9.9.2,所以手贱地试了试,太**了,没有括号匹配,并且调试和缩进和热键都很猥琐。

P.S.P.S.运行时界面没有停留,要最后加上for(;;);,提交前千万别忘了删掉!!!!!!否则TLE得死不瞑目(<---怒立flag)。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 #define N 601
 5 typedef long long ll;
 6 int Abs(const int &x){return x<0 ? (-x) : x;}
 7 struct Edge
 8 {
 9     int u,v,w;
10     Edge(const int &a,const int &b,const int &c){u=a;v=b;w=c;}
11     Edge(){}
12 }edges[(N*N)<<2];
13 bool operator < (const Edge &a,const Edge &b){return a.w<b.w;}
14 int n,m,K,fa[N*N],rank[N*N],a[N][N],nm,num[N][N],en,cnt[N*N],tot,ask_sum[N*N];
15 bool b[N*N];
16 ll ans;
17 void init(){for(int i=1;i<=nm;i++) fa[i]=i,cnt[i]=1,ask_sum[i]=b[i];}
18 int findroot(int x)
19 {
20     if(x==fa[x]) return x;
21     int rt=findroot(fa[x]);
22     fa[x]=rt;
23     return rt;
24 }
25 void Union(const int &U,const int &V)
26 {
27     if(rank[U]<rank[V]) fa[U]=V,cnt[V]+=cnt[U],ask_sum[V]+=ask_sum[U];
28     else
29       {
30         fa[V]=U; cnt[U]+=cnt[V]; ask_sum[U]+=ask_sum[V];
31         if(rank[U]==rank[V]) rank[U]++;
32       }
33 }
34 int main()
35 {
36     scanf("%d%d%d",&n,&m,&K); nm=n*m;
37     for(int i=1;i<=n;i++)
38       for(int j=1;j<=m;j++)
39         {
40           scanf("%d",&a[i][j]);
41           num[i][j]=++en;
42         } en=0;
43     for(int i=1;i<=n;i++)
44       for(int j=1;j<=m;j++)
45         scanf("%d",&b[num[i][j]]);
46     for(int i=1;i<=n;i++)
47       for(int j=1;j<=m;j++)
48         {
49           if(i!=n) edges[++en]=Edge(num[i][j],num[i+1][j],Abs(a[i][j]-a[i+1][j]));
50           if(j!=m) edges[++en]=Edge(num[i][j],num[i][j+1],Abs(a[i][j]-a[i][j+1]));
51         }
52     sort(edges+1,edges+en+1); init();
53     for(int i=1;i<=en;i++)
54       {
55         int f1=findroot(edges[i].u),f2=findroot(edges[i].v);
56         if(f1!=f2)
57           {
58             if(cnt[f1]+cnt[f2]>=K)
59               {
60                 if(cnt[f1]<K) ans+=((ll)edges[i].w*(ll)ask_sum[f1]);
61                 if(cnt[f2]<K) ans+=((ll)edges[i].w*(ll)ask_sum[f2]);
62               }
63             Union(f1,f2); tot++;
64             if(tot==nm-1) break;
65           }
66       }
67     printf("%I64d
",ans);
68     return 0;
69 }
原文地址:https://www.cnblogs.com/autsky-jadek/p/4069940.html