重心

HDU 4812 (点分治)

大兔子大兔子 提交于 2020-04-07 12:05:05
题目: https://vjudge.net/contest/307753#problem/E 题意: 给你一颗树,树上每个点都有个权值,现在问你是否存在 一条路径的乘积 mod 1e6+3 等于 k的路径,如果有找到字典序最小的方案 思路, 树上路径~点分治 我们能知道每条路径的值,现在我们可以转化的问题是,怎么找一条路径等于K,和两条路径的乘积等于K, 首先第一种很明显就是判断相不相等即可,第二种的话,我们知道所有路径,我们怎么找到O(n)找到两个呢,我们用个数组存下所有是否出现过,然后,其实就是一个简单的小学问题,我们枚举每个距离的时候相当于 x,y,z已经知道 x,z了,式子是x*y=z,我们就只要判断z/x是否在标记数组中出现过即可,又因为这个有mod ,所以我们只能去乘z的逆元,这个时间卡的有点紧,我加了输入挂,和预处理逆元,map标记都不能用,只能用普通标记数组。 然后还有一个问题,你是否能和之前那样直接求出来所有的距离,答案是否定的,因为你直接去遍历数组标记,数组中的路径还含有两个都是同一子树的情况,这种时候是不能加入标记数组的,但是怎么避免呢,这里用到一个巧妙地方法,我们直接在计算所有路径到重心的距离的时候去更新答案,因为我们只有得到一个子树所有答案的时候才会存入标记数组,这样就避免一个子树的路径发生冲突的情况。最后我们再清空掉我们当前重心存入的答案。

树分治之点分治模板总结

試著忘記壹切 提交于 2020-03-12 07:17:44
点分治的时间复杂度为O(NlogN)。 由于每次都是找重心,所以处理完一个大小为N的树后,每个子树的大小最大都为N/2,所以最多分治NlogN层,每层都是N 所以是O(NlogN)。 【具体流程】 1,选取一个点,将无根树变成有根树   为了使每次的处理最优,我们通常要选取树的重心。  何为“重心”,就是要保证与此点连接的子树的节点数最大值最小,可以防止被卡。  重心求法:   1。dfs一次,算出以每个点为根的子树大小。   2。记录以每个节点为根的最大子树大小   3。判断:如果以当前节点为根更优,就更新当前根。 void getroot(int v,int fa) { son[v] = 1; f[v] = 0;//f记录以v为根的最大子树的大小 for(int i = head[v];i;i=e[i].next) if(e[i].to != fa && !vis[e[i].to]) { getroot(e[i].to,v);//递归更新 son[v] += son[e[i].to]; f[v] = max(f[v],son[e[i].to]);//比较每个子树 } f[v] = max(f[v],sum-son[v]);//别忘了以v父节点为根的子树 if(f[v] < f[root]) root = v;//更新当前根 } 2、处理连通块中通过根节点的路径。   (注意

不规则图形重心

≯℡__Kan透↙ 提交于 2020-03-02 12:09:16
问题情境:   针对二维不规则图形(人体图像),寻找重心。 思路辨析:   1.注意区分于中心。中心横坐标是最小与最大横坐标的均值,纵坐标亦然。   2.可以参考重心概念公式,例如横坐标X=(x1m1+x2m2+‥+ximi)/M,其他方向坐标亦然。 解决办法:   1.自己做的方法就是简单把图形看做一个点m为1。附代码: private PointF getCore1(List<Point> points) { PointF core = new PointF(); float sumX = 0; float sumY = 0; foreach (Point point in points) { sumX += point.X; sumY += point.Y; } core = new PointF(sumX / (float)points.Count, sumY / (float)points.Count); return core; }   2.另外一种方法,暂不解其意,如有研究者,希望解惑。附代码: public static PointF getCore2(List<Point> mPoints) { double area = 0.0;//多边形面积 double Gx = 0.0, Gy = 0.0;// 重心的x、y for (int i = 1; i <=

LGOJ4299 首都

那年仲夏 提交于 2020-02-28 07:19:28
这题是 \(LCT\) 维护子树信息中的 \(LCT\) 维护重心 Description link 题意概述:给定一个森林,要求支持以下操作 1.链接两个点 2.求一个点所在树的重心 3.求所有重心编号的异或和 Solution \[Begin\] 看到有链接和询问操作的题目,我们想到了 \(LCT\) 首先是一些重心的性质,本题可以用到: \(1.\) 点到树上所有点的距离和最小的那个点就是中心 \(2.\) 重心在添加一条边之后只会移动最多一条边的距离 \(3.\) 如果我们联通森林里的两棵树,那么新树的重心就在原两树重心的路径上 应该都由重心的定义理解啥的易证吧 \(2333\) 然后我们在处理 \(2\) 操作的时候搞个并查集( \(findroot\) 好像很慢) 处理 \(3\) 操作的时候直接在链上进行类似二分查找的东西,看两侧子树的大小关系 \[Q.A.D\] \(P.s.\) 博主知道应该是 \(QED\) Code #include <bits/stdc++.h> using namespace std; #define int long long namespace yspm { inline int read() { int res = 0, f = 1; char k; while (!isdigit(k = getchar())) if (k == '

树的重心【模板】

白昼怎懂夜的黑 提交于 2020-02-25 18:11:19
知识点介绍 树的重心也就是树的质心,该点为根的有根树时,最大子树的节点数最小的根 碰到题目了再贴题 代码片 这边用链式前向星建图了 # include <bits/stdc++.h> using namespace std ; /* **树的重心:该点为根的有根树时,最大子树的节点数最小 */ const int N = 10005 ; struct edge { int to , next ; } e [ N ] ; int head [ N ] ; int cnt ; int n ; int num [ N ] ; //num[i]表示第i个点其子树的节点数 int root , ans = 1e9 ; //记录根 void add ( int x , int y ) { cnt ++ ; e [ cnt ] . to = y ; e [ cnt ] . next = head [ x ] ; head [ x ] = cnt ; } void find ( int x , int fa ) { num [ x ] = 1 ; //记录x的子树结点个数,为了反向求结点,得算上自己 int maxn = 0 ; //最大子树结点数 for ( int i = head [ x ] ; ~ i ; i = e [ i ] . next ) { int v = e [ i ] .

树的重心 & 连通图的划分

最后都变了- 提交于 2020-02-19 23:08:04
树的重心 树的重心的定义: 去掉这个点后,剩下的子树中节点最多的那棵树,的节点最少,那么这棵树,就是树的重心 const int N = 2e5 + 10 ; int e [ N ] , ne [ N ] , h [ N ] , len ; int n , ans , cnt [ N ] ; bool vis [ N ] ; int pos ; void dfs ( int u ) { vis [ u ] = true , cnt [ u ] = 1 ; //子树x的大小 int max_part = 0 ; //去调x以后 子树中最大的大小 for ( int i = h [ u ] ; ~ i ; i = ne [ i ] ) { int y = e [ i ] ; if ( vis [ y ] ) continue ; dfs ( y ) ; cnt [ u ] + = cnt [ y ] ; max_part = max ( max_part , cnt [ y ] ) ; } max_part = max ( max_part , n - cnt [ u ] ) ; if ( ans > max_part ) { ans = max_part ; //重心对应的子树的最大值 pos = u ; //重心所在的位置 } return ; } 连通图的划分 void dfs

NYOJ3——多边形重心问题

≯℡__Kan透↙ 提交于 2020-02-15 11:02:05
多边形重心问题 时间限制: 3000 ms | 内存限制: 65535 KB 难度: 5 描述:在某个多边形上,取n个点,这n个点顺序给出,按照给出顺序将相邻的点用直线连接, (第一个和最后一个连接),所有线段不和其他线段相交,但是可以重合,可得到一 个多边形或一条线段或一个多边形和一个线段的连接后的图形; 如果是一条线段,我们定义面积为0,重心坐标为(0,0).现在求给出的点集组成的图形的面积和重心横纵坐标 的和; 输入:第一行有一个整数0<n<11,表示有n组数据; 每组数据第一行有一个整数m<10000,表示有这个多边形有m个顶点; 输出:输出每个多边形的面积、重心横纵坐标的和,小数点后保留三位; 样例输入 3 3 0 1 0 2 0 3 3 1 1 0 0 0 1 4 1 1 0 0 0 0.5 0 1 样例输出 0.000 0.000 0.500 1.000 0.500 1.000 思路来源:http://blog.csdn.net/kay_zhyu/article/details/8805631 代码: #include<stdio.h> #include<math.h> const int N = 10001; struct POINT { double x; double y; }; POINT point[N]; int main() { int n,num,i;

nyoj 3 多边形重心问题

99封情书 提交于 2020-02-15 04:00:06
多边形重心问题 时间限制: 3000 ms | 内存限制: 65535 KB 难度: 5 描述   在某个多边形上,取n个点,这n个点顺序给出,按照给出顺序将相邻的点用直线连接, (第一个和最后一个连接),所有线段不和其他线段相交,但是可以重合,可得到一个多边形或一条线段或一个多边形和一个线段的连接后的图形;   如果是一条线段,我们定义面积为0,重心坐标为(0,0).现在求给出的点集组成的图形的面积和重心横纵坐标的和; 输入   第一行有一个整数0<n<11,表示有n组数据;   每组数据第一行有一个整数m<10000,表示有这个多边形有m个顶点; 输出   输出每个多边形的面积、重心横纵坐标的和,小数点后保留三位; 样例输入   3   3   0 1   0 2   0 3   3   1 1   0 0   0 1   4   1 1   0 0   0 0.5   0 1 样例输出   0.000 0.000   0.500 1.000   0.500 1.000 /** 注意: 1、浮点数定义为3位输出,但输出4位的原因 -- 未加换行符 分析: 1、因为n边形可以通过n个三角形组成,所以只需要计算n个三角形的面积; 2、通过叉积公式可以计算三角形面积 S = (B-->A(x)) * (C-->A(y)) - (C-->A(x)) * (B-->A(y)), 2.0

【学习笔记】[图论]树的重心

安稳与你 提交于 2020-02-14 20:31:06
非严格定义:树上任意一点都可以为根。对于某一点,若以它为根,则它的所有子树大小尽可能接近。 性质: 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个/多个重心,到他们的距离和一样。 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上。 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。 对于任意一棵树,叶子节点不可能是这棵树的重心。特别地,只有两个结点的树例外。 求解方法: 思考可以得出如下事实: 对于以任意一个结点作为根的所有最大子树中,以树的重心得出的最大子树最小。 所以,考虑用 DFS 遍历所有结点,每次求出以当前节点为根的最大子树的大小,记为 \(f_u\) 。设最终答案为 \(rt\) ,在遍历完某结点的所有儿子节点后,将求得的 \(f_u\) 与 \(f_{rt}\) 作比较,若小于,则令 \(rt=u\) 。 另外,还需要解决一个问题。如图: 记 \(size_u\) 为结点 \(u\) 的树的大小。如上图紫色数字所示。 不难发现,对于蓝色部分,只需要递归去扫一遍,把每棵子树的大小加起来就好了。了。但是,对于绿色部分,不难发现它原来属于红色结点的“父辈”。换而言之,我们无法通过递归的方式得出绿色部分的大小。 解决办法很简单:利用类似前缀和的思想,用整棵树的大小(记位 \(sum\) )减去除了“父辈

NYOJ 3(多边形重心)

断了今生、忘了曾经 提交于 2020-02-14 20:14:04
多边形重心问题 时间限制: 3000 ms | 内存限制: 65535 KB 难度: 5 描述 在某个多边形上,取n个点,这n个点顺序给出,按照给出顺序将相邻的点用直线连接, (第一个和最后一个连接),所有线段不和其他线段相交,但是可以重合,可得到一个多边形或一条线段或一个多边形和一个线段的连接后的图形; 如果是一条线段,我们定义面积为0,重心坐标为(0,0).现在求给出的点集组成的图形的面积和重心横纵坐标的和; 输入 第一行有一个整数0<n<11,表示有n组数据; 每组数据第一行有一个整数m<10000,表示有这个多边形有m个顶点; 输出 输出每个多边形的面积、重心横纵坐标的和,小数点后保留三位; 样例输入 3 3 0 1 0 2 0 3 3 1 1 0 0 0 1 4 1 1 0 0 0 0.5 0 1 样例输出 0.000 0.000 0.500 1.000 0.500 1.000 //http://www.cnblogs.com/jbelial/archive/2011/08/08/2131165.html //实际上没必要用结构体 #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int N = 10000; const double cmp = 1e-8;