首页 > 代码库 > 【kruscal】【最小生成树】【离线】洛谷 P2266 爱的距离

【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     else29       {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\n",ans);68     return 0;69 }

 

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