【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\n",ans);
68     return 0;
69 }
时间: 2024-12-10 10:35:32

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

洛谷2266 爱的距离

题目描述 Description 但好日子却不长久.Soha的手下大将恶魔猎手在此时背叛了他,自立为王,率领深藏在世界之轴的龙族叛变,并掳走了公主Ami.Soha在与恶魔猎手的战斗中,遭遇围杀,被困在一个荒芜人烟的大岛上.但在经过勘探后,他惊喜地发现,Ami也同时被恶魔猎手关押在这座岛上!经过精心研究,Soha发现关押Ami的地牢需要若干把钥匙才能打开,而钥匙则被埋藏在一系列的法阵中.凭借着自己的身手与魔力,Soha是能够破解法阵.获得钥匙的.法阵是一个M*N大小的矩阵,法阵中的每一格都具有自己

洛谷P1279 字串距离

P1279 字串距离 题目描述 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X的扩展串,这里“□”代表空格字符. 如果A1是字符串A的扩展串,B1是字符串B的扩展串,A1与B1具有相同的长度,那么我扪定义字符串A1与B1的距离为相应位置上的字符的距离总和,而两个非空格字符的距离定义为它们的ASCII码的差的绝对值,而空格字符与其他任意字符之间的距离为已知

洛谷 P1279 字串距离

题目描述 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X的扩展串,这里“□”代表空格字符. 如果A1是字符串A的扩展串,B1是字符串B的扩展串,A1与B1具有相同的长度,那么我扪定义字符串A1与B1的距离为相应位置上的字符的距离总和,而两个非空格字符的距离定义为它们的ASCII码的差的绝对值,而空格字符与其他任意字符之间的距离为已知的定值K,空格字符与空

洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

洛谷题目传送门 %%%天平巨佬和山楠巨佬%%% 他们的题解 思路分析 具体思路都在两位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 首先kruskal把最小生成树弄出来,因为要求次小生成树.至于为什么次小一定只在最小的基础上改变了一条边,我也不会证......打表找规律大法好 剩下的可以有一堆数据结构来维护最大值和次大值(原理两位巨佬都讲清楚了,这里只分析一下算法的优劣) 倍增+LCA 山楠巨佬的做法,我也写了这一种.复杂度\(O(MlogM(kruscal)+MlogN(

洛谷P1547 Out of Hay 最小生成树 并查集

洛谷P1547 Out of Hay 最小生成树 并查集 路径压缩 #include <cstdio> #include <cmath> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <iomanip> using namespace std ;

洛谷P1586 四方定理 动态规划 + 离线

洛谷P1586 四方定理动态规划 + 离线 1 #include <bits/stdc++.h> 2 #define For(i,j,k) for(int i=j;i<=k;i++) 3 using namespace std ; 4 5 const int N = 35011 ; 6 int n,T,ans ; 7 int f[5][N],a[211] ; 8 9 inline int read() 10 { 11 int x = 0 , f = 1 ; 12 char ch = ge

【C++】最近公共祖先LCA(Tarjan离线算法)&amp;&amp; 洛谷P3379LCA模板

1.前言 首先我们介绍的算法是LCA问题中的离线算法-Tarjan算法,该算法采用DFS+并查集,再看此算法之前首先你得知道并查集(尽管我相信你如果知道这个的话肯定是知道并查集的),Tarjan算法的优点在于相对稳定,时间复杂度也比较居中,也很容易理解(个人认为). 2.思想 下面详细介绍一下Tarjan算法的思想: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5.寻找与当前点

洛谷 P2155 BZOJ 2186 codevs 2301 [SDOI2008]沙拉公主的困惑

题目描述 大富翁国因为通货膨胀,以及假钞泛滥,政府决定推出一项新的政策:现有钞票编号范围为1到N的阶乘,但是,政府只发行编号与M!互质的钞票.房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量.现在,请你帮助沙拉公主解决这个问题,由于可能张数非常大,你只需计算出对R取模后的答案即可.R是一个质数.//codevs这里有坑,R是合数 输入输出格式 输入格式: 第一行为两个整数T,R.R<=10^9+10,T<=10000,表示该组中测试数据数目,R为模 后面T行,每行一对整数N,M,

洛谷P1265 公路修建(Prim)

To 洛谷.1265 公路修建 题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成. 修建工程分若干轮完成.在每一轮中,每个城市选择一个与它最近的城市,申请修建通往该城市的公路.政府负责审批这些申请以决定是否同意修建. 政府审批的规则如下: (1)如果两个或以上城市申请修建同一条公路,则让它们共同修建: (2)如果三个或以上的城市申请修建的公路成环.如下图,A申请修建公路AB,B申请修建公路BC,C申