[模板]洛谷·点分治
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;
}