[模板]洛谷·点分治


1、求树的重心

树的重心:若A点的子树中最大的子树的size[] 最小时,A为该树的中心

步骤:

  • 所需变量:siz[x] 表示 x 的子树大小(含自己),msz[x] 表示 其子树中最大的子树的大小,sum表示当前子树所有节点个数,root表示当前子树根节点
  • 处理出siz[x],msz[x]
  • 按最大子树最小的标准处理出root
inline void GetRoot(int x,int fa){
siz[x]=1;msz[x]=0;siz[x]//表示 x 的子树大小(含自己),msz[x] 表示其子树中最大的子树的大小
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(y==fa||vis[y])continue;
GetRoot(y,x);
siz[x]+=siz[y];
msz[x]=max(msz[x],siz[y]);
}
msz[x]=max(msz[x],sum-siz[x]);//按最大子树最小的标准处理出root
if(msz[x]<msz[root])root=x;
}
inline void GR_Init(int x,int fa){
sum=siz[x];//sum表示当前子树所有节点个数
root=0;//root表示当前子树根节点
GetRoot(x,fa);
}

2、分而治之

步骤:

  • 处理出经过这个节点的所有所求贡献
  • 减去其子树内不需要被计算但却被计算的贡献
  • 对其子树继续分治
inline void Point_Divide(int x){
vis[x]=1;
Calc(x,0,1);//处理出经过这个节点的所有所求贡献
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(vis[y])continue;
Calc(y,w[i],-1);//减去其子树内不需要被计算但却被计算的贡献
GR_Init(y,x);
Point_Divide(root);//对其子树继续分治
}
}

3、洛谷P3806点分治模板AC代码

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#define Rint register int
#define mem(a,b) memset(a,(b),sizeof(a))
using namespace std;
typedef long long LL;
template<typename T>inline void read(T &x){
x=0;T w=1,ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();
x=x*w;
}
inline void File(){
freopen("fuck.in","r",stdin);
freopen("fuck.out","w",stdout);
} const int maxn=100000+10,inf=0x7f7f7f7f;
int n,m;
int e,beg[maxn],nex[maxn<<1],to[maxn<<1],w[maxn<<1];
int dis[maxn],siz[maxn],dep[maxn],msz[maxn];
int sum,root,cnt;
int ask[maxn],ans[maxn];
bool vis[maxn]; inline void add(int x,int y,int z){
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
w[e]=z;
}
inline void GetRoot(int x,int fa){
siz[x]=1;msz[x]=0;//siz[x]表示 x 的子树大小(含自己),msz[x] 表示其子树中最大的子树的大小
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(y==fa||vis[y])continue;
GetRoot(y,x);
siz[x]+=siz[y];
msz[x]=max(msz[x],siz[y]);
}
msz[x]=max(msz[x],sum-siz[x]);//按最大子树最小的标准处理出root
if(msz[x]<msz[root])root=x;
}
inline void GR_Init(int x,int fa){
sum=siz[x];//sum表示当前子树所有节点个数
root=0;//root表示当前子树根节点
GetRoot(x,fa);
}
inline void GetDeep(int x,int fa){//处理深度
dis[++cnt]=dep[x];
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(vis[y]||y==fa)continue;
dep[y]=dep[x]+w[i];
GetDeep(y,x);
}
}
inline void GD_Init(int x,int val){
cnt=0;
dep[x]=val;
GetDeep(x,0);
}
inline void Calc(int x,int val,int mrk){//计算贡献
GD_Init(x,val);
sort(dis+1,dis+cnt+1);
for(Rint i=1;i<=m;i++){
for(Rint l=1,r=cnt;l<r;l++){
while(l<r&&dis[l]+dis[r]>=ask[i]){
if(dis[l]+dis[r]==ask[i])ans[i]+=mrk;
r--;
}
}
}
}
inline void Point_Divide(int x){
vis[x]=1;
Calc(x,0,1);//处理出经过这个节点的所有所求贡献
for(Rint i=beg[x];i;i=nex[i]){
int y=to[i];
if(vis[y])continue;
Calc(y,w[i],-1);//减去其子树内不需要被计算但却被计算的贡献
GR_Init(y,x);
Point_Divide(root);//对其子树继续分治
}
} int main(){
//File();
read(n);read(m);
for(Rint i=1;i<n;i++){
int x,y,z;read(x);read(y);read(z);
add(x,y,z);add(y,x,z);
}
for(Rint i=1;i<=m;i++)read(ask[i]);
msz[0]=inf;sum=n;GetRoot(1,0);
Point_Divide(root);
for(Rint i=1;i<=m;i++){
if(ans[i])printf("AYE\n");
else printf("NAY\n");
}
return 0;
}

模板·点分治(luogu P3806)的更多相关文章

  1. [luogu P3806] 【模板】点分治1

    [luogu P3806] [模板]点分治1 题目背景 感谢hzwer的点分治互测. 题目描述 给定一棵有n个点的树 询问树上距离为k的点对是否存在. 输入输出格式 输入格式: n,m 接下来n-1条 ...

  2. luoguP4721 【模板】分治 FFT

    P4721 [模板]分治 FFT 链接 luogu 题目描述 给定长度为 \(n-1\) 的数组 \(g[1],g[2],..,g[n-1]\),求 \(f[0],f[1],..,f[n-1]\),其 ...

  3. 洛谷 P4721 【模板】分治 FFT 解题报告

    P4721 [模板]分治 FFT 题目背景 也可用多项式求逆解决. 题目描述 给定长度为 \(n−1\) 的数组 \(g[1],g[2],\dots,g[n-1]\),求 \(f[0],f[1],\d ...

  4. LG4721 【模板】分治 FFT

    P4721 [模板]分治 FFT 题目背景 也可用多项式求逆解决. 题目描述 给定长度为 $n-1$ 的数组 $g[1],g[2],..,g[n-1]$,求 $f[0],f[1],..,f[n-1]$ ...

  5. Luogu P3806 点分治模板1

    题意: 给定一棵有n个点的树询问树上距离为k的点对是否存在. 分析: 这个题的询问和点数都不多(但是显然暴力是不太好过的,即使有人暴力过了) 这题应该怎么用点分治呢.显然,一个模板题,我们直接用套路, ...

  6. [洛谷P3806] [模板] 点分治1

    洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...

  7. Luogu 4721 【模板】分治 FFT

    还不会这题的多项式求逆的算法. 发现每一项都是一个卷积的形式,那么我们可以使用$NTT$来加速,直接做是$O(n^2logn)$的,我们考虑如何加速转移. 可以采用$cdq$分治的思想,对于区间$[l ...

  8. [题解] Luogu P4721 【模板】分治 FFT

    分治FFT的板子为什么要求逆呢 传送门 这个想法有点\(cdq\)啊,就是考虑分治,在算一段区间的时候,我们把他分成两个一样的区间,然后先做左区间的,算完过后把左区间和\(g\)卷积一下,这样就可以算 ...

  9. 树的点分治 板题 Luogu P3806

    给定一棵有n个点的树 询问树上距离为k的点对是否存在. AC code: #include<bits/stdc++.h> using namespace std; const int MA ...

随机推荐

  1. LODOP弹出对话框获取保存文件的路径

    通常一般不会让用户自己在文本框里填上路径,因为路径要输入字母字符等比较麻烦,而且用户硬盘里文件很多,也不知道要保存在哪里,LODOP可以弹出一个选择保存路径的弹窗,然后把返回选择的路径值.这样用户就可 ...

  2. Conjugate Function

    共轭函数 共轭函数的定义: 设函数f:Rn→R,定义函数f∗:Rn→R为: f∗(y)=sup(<y,x>−f(x))  x∈D 此函数称为函数f的共轭函数.即函数yx和函数f(x)之间差 ...

  3. codeforces9A

    Die Roll CodeForces - 9A Yakko,Wakko和Dot,世界著名的狂欢三宝,哈哈,不知道你是否看过这个动画片. 某一天,过年了,他们决定暂定卡通表演,并去某些地方旅游一下.Y ...

  4. codeforces279B

    Books CodeForces - 279B When Valera has got some free time, he goes to the library to read some book ...

  5. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  6. HDU4409-LCA模拟

    给一个家谱,回答给的操作结果. 1)L 按照字典序排序儿子,输出整个家谱. 2)b 求出所给name的所有兄弟. 3)c 求出两个name的LCA 读入数据时,我用一个curfather数组维护固定深 ...

  7. day5 continue 和 break的区别

    # continue num = 1 while num <=10: num += 1 if num == 3: continue print(num) # continue 表示跳出本次循环后 ...

  8. float 、double 加减乘除出现小数位多出的问题

    /** * 提供精確的加法運算 * @param args */ public static double add(double v1, double v2) { BigDecimal b1 = ne ...

  9. java 按概率产生

    import java.util.Random; import org.junit.Test; public class Demo1 { public void getChance(int perce ...

  10. 架构师成长之路6.1 DNS理论

    点击返回架构师成长之路 架构师成长之路6.1 DNS理论 1.DNS一些基本概念       ① FQDN:Full Qualified Domain Name,完全限定域名,即每个域在全球网络都是唯 ...