[bzoj2599][IOI2011]Race_树上点分治】的更多相关文章

Race bzoj-2599 题目大意:询问一颗树上最短的.长度为k的链,边有边权,n个节点. 注释:$1\le n \le 2\cdot 10^5$,$1\le k \le 10^6$. 想法:树上点分治的另一种表现方式.首先,由于题目中要求的是最小值,我们发现这东西可加不可减.不可减意味着什么?意味着我们递归计算当前树时无法将它的单个子树的情况减掉.所以之前的单步容斥的算法就收到了打压qwq.我们思考另一种方法.首先,类似于dfs的,我一定是对于当前root一颗子树一颗子树地递归,只有当前子…
写了四五道点分治的题目了,算是比较理解点分治是什么东西了吧= = 点分治主要用来解决点对之间的问题的,比如距离为不大于K的点有多少对. 这道题要求距离等于K的点对中连接两点的最小边数. 那么其实道理是一样的.先找重心,然后先从重心开始求距离dis和边数num,更新ans,再从重心的儿子开始求得dis和num,减去这部分答案 因为这部分的答案中,从重心开始的两条链有重叠部分,所以要剪掉 基本算是模板题,但是减去儿子的答案的那部分还有双指针那里调了好久,所以还不算特别熟练.. PS跑了27秒慢到飞起…
题目描述 给一棵树,每条边有权.求一条简单路径,权值和等于 K,且边的数量最小. 题解 比较明显需要用到点分治,我们定义\(d\)数组表示当前节点到根节点\(rt\)之间有多少个节点,也可以表示有多少条边,然后我们在定义\(dis\)表示当前节点到根节点\(rt\)的距离,那么我们就可以得到\(ans=min(ans,d[u]+t[k-dis[u]])\),这个方程还是比较容易的. 但是这道题目不满足状态可减性,说的明白一点就是答案和答案之间无法相减,那么点分治的容斥原理处理就可以变成将原来没有…
传送门 题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 思路: 考虑点分治如何合并. 我们利用树形dpdpdp求树的直径的方法,边dfsdfsdfs子树边统计答案即可. 代码: #include<bits/stdc++.h> #define ri register int #define fi first #define se second using namespace std; typedef pair<int,int> pii; inline int…
题目 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 输入格式 第一行 两个整数 n, k 第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) 输出格式 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 输入样例 4 3 0 1 1 1 2 2 1 3 4 输出样例 2 提示 2018.1.3新加数据一组,未重测 题解 比较常规的点分治,然而我还是因为不熟练写漏一个判定T得停不下来QA…
BZOJ_2599_[IOI2011]Race_点分治 Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k 第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Output 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 Sample Input 4 3 0 1 1 1 2 2 1 3 4 Sample Output 2 点…
Brief Description 给定一棵带权树,你需要找到一个点对,他们之间的距离为k,且路径中间的边的个数最少. Algorithm Analyse 我们考虑点分治. 对于子树,我们递归处理,所以我们只考察经过重心的情况. 我们很容易把所有点的dist和deep预处理出来,所以,问题就转化成了求一个点对,使得 \(dist[i]+dist[j] = K\ and\ Belong[i] \neq Belong[j]\) 开始的时候,我想:这题我做过的!不就是在数列里面设两个指针吗? 然后,我…
[BZOJ2599]Race(点分治) 题面 BZOJ权限题,洛谷 题解 好久没写过点分治了... 在ppl的帮助下终于想起来了 orz ppl 首先回忆一下怎么求有没有正好是\(K\)的路径 维护一个表示距离的桶 对于当前重心,依次插入每棵子树的距离值 然后检查是否存在即可 显然加一步,求最短的路径数 那么,把原来的是否存在的01数组 改为记录最短路径数的一个\(int\)数组 每次插入的时候去取\(min\)就行了 #include<iostream> #include<cstdio…
链接:https://codeforces.com/contest/161/problem/D 题意:给一个树,求距离恰好为$k$的点对是多少 题解:对于一个树,距离为$k$的点对要么经过根节点,要么跨过子树的根节点,于是考虑树分治 用类似poj1741的想法,可以推出: 对于任意一棵子树,其根节点记为$C$,其子树中: 记距离$C$距离之和为$k$的点对数量$S_{c}$ 记$C$儿子节点$C_1...C_n$的子树中,距离$C_i$距离为$k-2$的点对数量为$S'_{c_i}$ 其符合条件…
题目链接:http://poj.org/problem?id=1741 题意: 给定一棵包含$n$个点的带边权树,求距离小于等于K的点对数量 题解: 显然,枚举所有点的子树可以获得答案,但是朴素发$O(n^2logn)$算法会超时, 利用树的重心进行点分治可以将$O(n^2logn)$的上界优化为近似$O(nlogn)$ 足以在1000ms的测试时间内通过 具体原理参考注释 #include<iostream> #include<map> #include<string>…
寻找树上存在长度为k点对,树上的分治  代码和  这个  差不多 ,改一下判断的就好 #include <iostream> #include <algorithm> #include <cstdio> #include <vector> #include <string.h> using namespace std; ; ],to[maxn*],numofE,dist[maxn*]; void add(int u,int v, int d) {…
Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. Wri…
Description 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 Input 第一行 两个整数 n, k 第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) Output 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 Sample Input 4 3 0 1 1 1 2 2 1 3 4 Sample Output 2 Solution 开一个100W的数组t,t[i]表示到当…
给nlog2n随便过的跪了,不得已弄了个哈希表伪装成nlogn(当然随便卡,好孩子不要学)…… 不过为啥哈希表的大小开小点就RE啊……?必须得超过数据范围一大截才行……谜 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int f,c; inline void R(int &x){ c=0;f=1; for(;c<'0'||c>'9';c=getc…
两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调整二分上界.假设一棵树树根为x,要求就是经过树根x的最大答案,不经过树根x的可以递归求解.假设B[i]为当前做到的一颗x的子树中的点到x的距离为i的最大权值,A[i]为之前已经做过的所有子数中的点到x的距离为i的最大权值(这里的权值是Σv(e)-i*avgvalue),那么对于当前子树的一个距离i,…
我们都做过一道题(?)货币兑换,是用cdq分治来解决不单调的斜率优化 现在它放到了树上.. 总之先写下来dp方程,$f[i]=min\{f[j]+(dis[i]-dis[j])*p[i]+q[i]\} ,j是i的祖先,dis[i]-dis[j]<=l[i]$ ,其中dis[i]表示1号点到i号点的距离 可以很明显的看出斜率优化,但我们要放到树上做 于是就运用点分治的思想来找重心(正如普通的cdq是找中点一样) 步骤是这样的: 1.对于根为x的一个子树,我们先找到它的重心rt 2.把rt的子树刨掉…
自闭了几天后的我终于开始做题了..然后调了3h一道点分治板子题,调了一天一道IOI... 最后还是自己手造数据debug出来的... 这题一看:树上路径问题,已知路径长度求balabala,显然是点分治(其实只要有一点点对点分治思想及应用的理解就能知道).照普通点分治的做法,找重心分治,每次统计子树所有点到根的距离,然后开个桶判断一下是否出现即可(本题还要存一下边数).然后我们要做的只有暴力统计取min了,时间复杂度\(O(n\log n)\). 于是本蒟蒻自信满满地打下了以下代码: #incl…
题目链接 题意 给一棵边带权树,问两点之间的距离小于等于K的点对有多少个. 思路 <分治算法在树的路径问题中的应用> 图片转载于http://www.cnblogs.com/Paul-Guderian/p/6782671.html 我对于点分治的理解:对于树上的一些问题,可以转化为答案只与当前根有关的问题,然后分治递归求解每一棵子树,统计答案.找的根应当是当前子树的重心,具体证明可以看上面的论文. 对于当前正在处理的树,这棵树的路径有两种情况: 经过根结点. 不经过根节点(在子树内). 对于第…
做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以,如果是有坐标不递增的斜率优化的话就用 CDQ 分治先处理出左半部分答案,然后将处理好的左区间答案用来更新右区间. 那么,将序列问题拓展到树上后,我们也要选择一个合适的中点来保证分治层数不多,且区间大小均匀. 而树中这个"中点"就是一棵树的重心!! 即当我们处理以 $x$ 为根的子树时(分治…
传送门 点分治,黄学长的选根方法会T掉,换了这个人的选根方法就可以了. 当然,你也可以选择黄学长的奇淫优化 //BZOJ 2599 //by Cydiater //2016.9.23 #include <iostream> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <ctim…
0.题意:给一棵树,每条边有权.求一条路径,权值和等于K,且边的数量最小. 1.分析:水题一道,一波树分治就好 我们可以发现这个题的K是比较小的,才100w,那么我们可以树分治一下,在遍历每一棵子树的时候我们知道要统计两个不同子树之间的权值,如果我们全遍历然后再getans,我们就会发现某个子树自己会和自己进行统计了一下,这样不太好,所有我们每遍历一个子树我们就把这个子树中从x所有长度为k的路径记录上v[k]=边数,记住要取min,然后询问我们还是遍历子树,我们查询v[K - k]然后统计答案.…
[题意] 问树中长为k的路径中包含边数最少的路径所包含的边数. [思路] 统计经过根的路径.假设当前枚举到根的第S个子树,若x属于S子树,则有: ans<-dep[x]+min{ dep[y] },y属于前S-1个子树,dis[x]<=K 所以只需要用一个数组t[len]记录前S-1棵子树中长度为len的最少边数即可.t只用开到K的最大值. 然后分治处理子树. [代码] #include<set> #include<cmath> #include<queue>…
树上路径的f(u,v)=路径上所有点的乘积. 树上每个点的权值都是由给定的k个素数组合而成的,如果f(u,v)是立方数,那么就说明f(u,v)是可行的方案. 问有多少种可行的方案. f(u,v)可是用状态压缩来表示,因为最多只有30个素数, 第i位表示第i个素数的幂,那么每一位的状态只有0,1,2因为3和0是等价的,所以用3进制状态来表示就行了. 其他代码就是裸的树分. 另外要注意的是,因为counts函数没有统计只有一个点的情况,所以需要另外统计. #pragma warning(disabl…
题意是说给了n个点的树n<=10000,问有多少个点对例如(a,b)他们的之间的距离小于等于k 采用树的分治做 #include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #include <vector> using namespace std; ; ],to[maxn*],numofE,dist[maxn*]; void add(int u…
http://www.lydsy.com/JudgeOnline/problem.php?id=2599 点分治 mi[i] 记录边权和为i时的最少边数 先更新答案,再更新mi数组,换根时清空mi #include<cstdio> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; #define N 200001 #define K 1000001 in…
点此看题面 大致题意: 给你一棵树,问长度为\(K\)的路径至少由几条边构成. 点分治 这题应该比较显然是点分治. 主要思路 与常见的点分治套路一样,由于\(K≤1000000\),因此我们可以考虑开个桶\(f\)数组来记录每种长度的路径至少由几条边构成. 但是要注意,每换一个根要将桶清空! 呃,暴力清空肯定\(T\)飞. 于是就需要再开一个\(g\)数组,记录每个答案是在以哪一个节点为根时求出来的,这样就可以避免清空数组了.这也是一个比较常用的套路. 其余的过程与点分板子差不多,就不多说了.…
点分治,用一个mn[v]数组记录当前root下长为v的链的最小深度,每次新加一个儿子的时候都在原来儿子更新过的mn数组里更新ans(也就是查一下mn[m-dis[p]]+de[p]) 这里注意更新和初始化的时候不能对整个mn操作,这样时间复杂度是错的,要开一个栈存一下更新了哪些点,只初始化这些点即可 #include<iostream> #include<cstdio> using namespace std; const int N=1000005; int n,m,h[N],c…
题目链接 题意 给一棵树,每个点上有一个权值,问是否存在一条路径(不能是单个点)上的所有点相乘并对1e6+3取模等于k,输出路径的两个端点.如果存在多组答案,输出字典序小的点对. 思路 首先,(a * b) % MOD = k,知道a和k,求b,可以使用逆元来求,于是可以想到用一个类似于map的东西(我这里的Hash数组,记录值为i的时候它的最小下标是多少)存路径长度为b的时候,那个端点是哪个点. 但是我一开始是想着先全部处理好,然后再O(MOD)判一遍,但是发现这种做法的话在有删除的情况下难以…
点分治的写法1: 题目链接:https://www.luogu.org/problem/P3806 题意:给出一颗带边权的树,结点数n<=1e4,每条边有权值<=1e4,有m组询问(m<=100),每组询问为一个k,表示是否存在一条路经长度为k,存在输出AYE,不存在输出NAY. 思路:点分治模板题,第一次学点分治.这位聚聚的讲解特别好,安利一波:https://blog.csdn.net/a_forever_dream/article/details/81778649. 写法1:先计算…
题意:给一个N个节点的带权树,求长度小于等于K的路径条数 思路:选取一个点作为根root,假设f(root)是当前树的答案,那么答案来源于两部分: (1)路径不经过root,那么就是完全在子树内,这部分可以递归统计 (2)路径经过root,这部分可以通过容斥原理统计,具体见有关点分治资料... 点分治有个特点,当考虑的问题由根这个子树转为儿子的子树时,可以选取任意点作为新的根,只要它在儿子的子树内,这就使得我们可以通过选取特别的点使得树深度更小,这个点就是树的重心(在程序里面是不断找子树的重心)…