【洛谷P3806 点分治】
题目描述
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
输入格式:
n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径
接下来m行每行询问一个K
输出格式:
对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)
输入样例:
2 1 1 2 2 2
输出样例:
AYE
题解:
离线处理,先对这棵树进行点分治,可以预处理出来每种长度的边有没有出现过,然后再判断即可。
对于每个子问题,由重心出发dfs,把所有深度两两相加,打标记(根深度为0),然后有两个点都属于同一个子树,那么这两个节点算出来的答案是不存在的,再以重心的儿子开始dfs(深度与第一次dfs相同)把其中所有深度两两删掉即可。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 struct nd{ 8 int to,next,v; 9 } e[20005]; 10 int head[10005],dep[10005],d[10005],mx[10005],sz[10005]; 11 bool vis[10005]; 12 int t[10000005]; 13 int sum,ans,rt; 14 int n,k,cnt,m; 15 inline void insert(int u,int v,int w){ 16 e[++cnt].next=head[u]; 17 head[u]=cnt; 18 e[cnt].to=v; 19 e[cnt].v=w; 20 } 21 inline void findG(int now,int fa){ 22 mx[now]=0; 23 for(int i=head[now];i;i=e[i].next){ 24 if(e[i].to==fa || vis[e[i].to]) continue; 25 findG(e[i].to,now); 26 mx[now]=max(mx[now],sz[e[i].to]); 27 } 28 mx[now]=max(mx[now],sum-sz[now]); 29 if(mx[now]<mx[rt]) rt=now; 30 } 31 inline void findS(int now,int fa){ 32 sz[now]=1; 33 for(int i=head[now];i;i=e[i].next){ 34 if(vis[e[i].to] || e[i].to==fa) continue; 35 findS(e[i].to,now); 36 sz[now]+=sz[e[i].to]; 37 } 38 } 39 inline void findD(int now,int fa){ 40 dep[++dep[0]]=d[now]; 41 for(int i=head[now];i;i=e[i].next){ 42 if(vis[e[i].to] || e[i].to==fa) continue; 43 d[e[i].to]=d[now]+e[i].v; 44 findD(e[i].to,now); 45 } 46 } 47 inline int cal(int now,int x,int k){ 48 d[now]=x;dep[0]=0; 49 findD(now,-1); 50 int num=0,l,r; 51 for(int i=1;i<=dep[0];i++) 52 for(int j=i+1;j<=dep[0];j++) 53 t[dep[i]+dep[j]]+=k; 54 } 55 inline void work(int x) 56 { 57 cal(x,0,1); 58 vis[x]=1; 59 for(int i=head[x];i;i=e[i].next){ 60 if(vis[e[i].to]) continue; 61 cal(e[i].to,e[i].v,-1); 62 findS(e[i].to,x); 63 sum=sz[e[i].to]; 64 rt=0; 65 findG(e[i].to,x); 66 work(rt); 67 } 68 } 69 int main(){ 70 int u,v,w,x; 71 scanf("%d%d",&n,&m); 72 for(int i=1;i<n;i++){ 73 scanf("%d%d%d",&u,&v,&w); 74 insert(u,v,w); 75 insert(v,u,w); 76 } 77 rt=0; 78 mx[rt]=1e9+7; 79 findS(1,-1); 80 sum=sz[1]; 81 findG(1,-1); 82 work(rt); 83 for(int i=1;i<=m;i++){ 84 scanf("%d",&x); 85 if(t[x]>=1) printf("AYE\n"); 86 else printf("NAY\n"); 87 } 88 }