P3806 模板点分治1
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3806 模板点分治1相关的知识,希望对你有一定的参考价值。
题意:
给定一棵有 n 个点的树,询问树上距离为 k 的点对是否存在。
题解:
因为题目是要求路径长为k的路径条数,所以solve函数返回的是过x节点的长度为k的路径。
而这路径长度是可以用
O
(
n
)
O(n)
O(n) 的方法求出
点分治,没啥好说的。
#include<bits/stdc++.h>
#define endl '\\n'
#define int long long
using namespace std;
const int maxn=2e5+10;
struct E{
int to,w,next;
}edge[maxn];
int head[maxn],cnt;
int maxp[maxn],dis[maxn],sz[maxn];
bool visited[maxn],judge[10000000];
int sum,rt,q[maxn],nowcnt,temp[maxn];
int n,m;
void getrt(int x,int fa){
sz[x]=1,maxp[x]=0;//maxp初始化为最小值
//遍历所有儿子,用maxp保留最大大小的儿子大小
for(int i=head[x];~i;i=edge[i].next){
int to=edge[i].to;
//int w=edge[i].w;
if(to==fa||visited[to]) continue; //被删掉的也不算
getrt(to,x);
sz[x]+=sz[to];
if(sz[to]>maxp[x]) maxp[x]=sz[to]; //更新maxp
}
maxp[x]=max(maxp[x],sum-sz[x]);
if(maxp[x]<maxp[rt]) rt=x;
}
void add(int u,int v,int w){
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void getdis(int x,int fa){
temp[nowcnt++]=dis[x];
for(int i=head[x];~i;i=edge[i].next){
int v=edge[i].to;
if(v==fa||visited[v]) continue;
dis[v]=dis[x]+edge[i].w;
getdis(v,x);
}
}
int ans[105];
void sol(int x){
queue<int> que;
for(int i=head[x];~i;i=edge[i].next){
int v=edge[i].to;
if(visited[v]) continue;
nowcnt=0; //注意置零计数器
dis[v]=edge[i].w;
getdis(v,x); //把距离都处理出来
for(int j=0;j<nowcnt;j++){ //遍历所有距离
for(int k=1;k<=m;k++){ //遍历所有询问
if(q[k]>=temp[j]){ //如果询问大于单条路径的长度,就有可能存在
ans[k]|=judge[q[k]-temp[j]];
}
}
}
for(int j=0;j<nowcnt;j++){ //把存在的单挑路径长度标为true,供下文使用
que.push(temp[j]);
judge[temp[j]]=true;
}
}
while(!que.empty()){
judge[que.front()]=false;
que.pop();
}
}
void divide(int x){
visited[x]=judge[0]=true; //删除根
sol(x); //计算经过根节点的路径
for(int i=head[x];~i;i=edge[i].next){
int v=edge[i].to;
if(visited[v]) continue;
maxp[rt=0]=sum=sz[v]; //重心设为0,把maxp[0]至为最大值
getrt(v,0);
getrt(rt,0); //与主函数相同
divide(rt);
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(head,-1,sizeof head);
memset(visited,false,sizeof visited);
cin>>n>>m;
sum=n;
for(int i=1;i<n;i++){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
maxp[0]=sum=n; //maxp[0]设为最大值
getrt(1,0); //找重心
getrt(rt,0); //此时siz数组存放的是1为根的时的大小,需要以找出的重心为根重算。
for(int i=1;i<=m;i++) cin>>q[i];
divide(rt); //找好重心就可以分治了
for(int i=1;i<=m;i++){
if(ans[i]) cout<<"AYE"<<endl;
else cout<<"NAY"<<endl;
}
}
以上是关于P3806 模板点分治1的主要内容,如果未能解决你的问题,请参考以下文章