模板·点分治(luogu P3806)
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)的更多相关文章
- [luogu P3806] 【模板】点分治1
[luogu P3806] [模板]点分治1 题目背景 感谢hzwer的点分治互测. 题目描述 给定一棵有n个点的树 询问树上距离为k的点对是否存在. 输入输出格式 输入格式: n,m 接下来n-1条 ...
- luoguP4721 【模板】分治 FFT
P4721 [模板]分治 FFT 链接 luogu 题目描述 给定长度为 \(n-1\) 的数组 \(g[1],g[2],..,g[n-1]\),求 \(f[0],f[1],..,f[n-1]\),其 ...
- 洛谷 P4721 【模板】分治 FFT 解题报告
P4721 [模板]分治 FFT 题目背景 也可用多项式求逆解决. 题目描述 给定长度为 \(n−1\) 的数组 \(g[1],g[2],\dots,g[n-1]\),求 \(f[0],f[1],\d ...
- LG4721 【模板】分治 FFT
P4721 [模板]分治 FFT 题目背景 也可用多项式求逆解决. 题目描述 给定长度为 $n-1$ 的数组 $g[1],g[2],..,g[n-1]$,求 $f[0],f[1],..,f[n-1]$ ...
- Luogu P3806 点分治模板1
题意: 给定一棵有n个点的树询问树上距离为k的点对是否存在. 分析: 这个题的询问和点数都不多(但是显然暴力是不太好过的,即使有人暴力过了) 这题应该怎么用点分治呢.显然,一个模板题,我们直接用套路, ...
- [洛谷P3806] [模板] 点分治1
洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...
- Luogu 4721 【模板】分治 FFT
还不会这题的多项式求逆的算法. 发现每一项都是一个卷积的形式,那么我们可以使用$NTT$来加速,直接做是$O(n^2logn)$的,我们考虑如何加速转移. 可以采用$cdq$分治的思想,对于区间$[l ...
- [题解] Luogu P4721 【模板】分治 FFT
分治FFT的板子为什么要求逆呢 传送门 这个想法有点\(cdq\)啊,就是考虑分治,在算一段区间的时候,我们把他分成两个一样的区间,然后先做左区间的,算完过后把左区间和\(g\)卷积一下,这样就可以算 ...
- 树的点分治 板题 Luogu P3806
给定一棵有n个点的树 询问树上距离为k的点对是否存在. AC code: #include<bits/stdc++.h> using namespace std; const int MA ...
随机推荐
- BZOJ4372 烁烁的游戏(动态点分治+线段树)
建出点分树,每个节点维护其作为点分树上lca对子树内点的贡献,线段树维护即可,同时另开一个线段树以减掉父亲重复的贡献. #include<iostream> #include<cst ...
- Leetcode 66.加一 By Python
思路 如果单独操作最后一个元素,令其加一,满十进一,会挺麻烦的,要分情况. 所以我的思路是将list还原到字符串,再变成数值,直接+1,然后再还原到list.详见代码 代码 class Solutio ...
- 【转】19个必须知道的Visual Studio快捷键
本文将为大家列出在Visual Studio中常用的快捷键,正确熟练地使用快捷键,将大大提高你的编程工作效率. 项目相关的快捷键 Ctrl + Shift + B = 生成项目 Ctrl + Alt ...
- tjoi2018D2T2(luogu4590) 游园会 (状压dp)
题解劝退系列 设长的那个串是A,短的那个串是B. 那我们在如果已经知道某个A的时候,A[1..i]和B[1..j]的最长公共子序列$f[i][j]=max\{f[i-1][j],f[i][j-1],f ...
- 标准C++类std::string的内存共享和Copy-On-Write...
标准C++类std::string的 内存共享和Copy-On-Write技术 陈皓 1. 概念 Scott Meyers在<More Effective C++>中举了个例子,不知你是否 ...
- (转)Maven之自定义archetype生成项目骨架
背景:最近在开发一个项目的基础构件,在以后项目的开发过程中可以直接使用该构件快速的生成项目骨架进行开发. 摘要:使用过Maven的人都知道maven中有许多功能都是通过插件来提供的,今天我们来说一下其 ...
- 收藏:SQL重复记录查询 .
来自:http://blog.csdn.net/chinmo/article/details/2184020 1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断select ...
- Eclipse导入jdk的源码
eclipse导入JDK源码 前言:这件事情的重要性不言而喻,对于学习和观摩优秀的代码非常的有用,我喜欢想看什么代码都能 Ctrl+鼠标一点 就能够看到,不过这个不常操作,在这里小记一笔,以备后用.( ...
- JAVA记录-Servlet介绍
1.什么是Servlet Servlet是sun公司提供的一门用于开发动态web资源的技术.Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向 ...
- C#常用的正则工具类写法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...