【bzoj1316】【树上的询问】点分治+set

àì夳堔傛蜴生んèń 2022-03-15 09:48 216阅读 0赞

【bzoj1316】【树上的询问】点分治+set

Description
一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No.
Input
第一行两个整数n, p分别表示点的个数和询问的个数. 接下来n-1行每行三个数x, y, c,表示有一条树边x→y,长度为c. 接下来p行每行一个数Len,表示询问树中是否存在一条长度为Len的路径.
Output
输出有p行,Yes或No.
Sample Input
6 4
1 2 5
1 3 7
1 4 1
3 5 2
3 6 3
1
8
13
14
Sample Output
Yes
Yes
No
Yes

HINT
30%的数据,n≤100.
100%的数据,n≤10000,p≤100,长度≤1000000.

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. struct Node{int to,v;};
  4. set<int> res;
  5. vector<Node> G[10005];
  6. Node e;
  7. int v[10005],n,m,sim[10005],mos[10005],MX=0x3f3f3f3f,root,a,b,w,dis[10005];
  8. void getroot(int u,int fa){
  9. sim[u]=1;mos[u]=0;
  10. v[u]=1;
  11. for(int i=0;i<G[u].size();i++){
  12. e=G[u][i];
  13. if(v[e.to]||e.to==fa)continue;
  14. getroot(e.to,u);
  15. sim[u]+=sim[e.to];
  16. mos[u]=max(mos[u],sim[e.to]);
  17. }
  18. mos[u]=max(mos[u],n-sim[u]);
  19. if(MX>mos[u]){
  20. root=MX;
  21. MX=mos[u];
  22. }
  23. }//找到一个根
  24. void getans(int u,int fa,int d,set<int> ans){
  25. for(int i=0;i<G[u].size();i++){
  26. e=G[u][i];
  27. if(e.to==fa)continue;
  28. ans.insert(d+e.v);
  29. getans(e.to,u,d+e.v,ans);
  30. }
  31. }
  32. //首先对根进行加乘 再依次对每个点进行加乘
  33. void divide(int u,int fa){
  34. v[u]=1;
  35. vector<set<int> > all;
  36. for(int i=0;i<G[u].size();i++){
  37. set<int> ans;
  38. e=G[u][i];
  39. if(v[e.to]||e.to==fa)continue;
  40. ans.insert(e.v);//每条边都加上
  41. getans(e.to,u,e.v,ans);//找这个子树的所有通过节点u的边
  42. all.push_back(ans);//子树所有点距离该点的长度加到vector里面
  43. }
  44. cout<<all.size()<<endl;
  45. for(int i=0;i<all.size();i++){
  46. set<int> ans=all[i];
  47. for(set<int>::iterator it=ans.begin();it!=ans.end();it++){
  48. for(int j=i+1;j<all.size();j++){
  49. for(set<int>::iterator ti=(all[j]).begin();ti!=(all[j]).end();ti++){
  50. res.insert(*it+*ti);
  51. }
  52. }
  53. }
  54. }
  55. }
  56. int main(){
  57. cin>>n>>m;
  58. for(int i=1;i<n;i++){
  59. cin>>a>>b>>w;
  60. e.to=b;e.v=w;
  61. G[a].push_back(e);
  62. e.to=a;
  63. G[b].push_back(e);
  64. }
  65. getroot(1,0);
  66. memset(v,0,sizeof(v));
  67. divide(root,0);//初始化完毕,开始进行输出
  68. cout<<res.size()<<endl;
  69. for(int i=1;i<=m;i++){
  70. cin>>a;
  71. if(res.count(a)) cout<<"Yes"<<endl;
  72. else cout<<"No"<<endl;
  73. }
  74. return 0;
  75. }

发表评论

表情:
评论列表 (有 0 条评论,216人围观)

还没有评论,来说两句吧...

相关阅读

    相关 BZOJ1095 动态分治(分树)

    题意: 操作1.修改一个点的颜色(黑白互换) 操作2.询问所有黑色点之间最远距离   点分树:当我们可以形如点分治一样的统计答案,即每次确定一个重心,然后计算他们子树之

    相关 分治-模板

    可能一步步克服恐惧的过程就是成功,所以只管面对恐惧,不思考结果, 24分钟敲模板,这是点分治第一次敲的这么顺利,纪念一下。 洛谷:2634.求距离是三的倍数的点对数

    相关 询问

    题目 三国杀中,君主有5滴血,武将有4滴血,文官有3滴血。 输入 在输入中K代表君主,L代表文官,R代表武将,输入格式先是一个sum (sum < 100) 表述测试

    相关 分治初步

      点分治是一种常用于处理树上点对关系的分治算法。   一、算法介绍   提到点分治,我们先来看一道例题:[洛谷P3806 【模板】点分治1][P3806 _1]

    相关 分治学习笔记

    哗我看了一下好像没有很详细专门讲分治的blog?那就主要先学一下点分治吧,其他的……等我记得把C++一本通带到机房来再说吧先咕着啦 > 写在前面 > > 刷题进度 > >

    相关 分治

      [传送门][Link 1](洛谷) UPDATE:关于代码中时间复杂度的更正——在代码中每一次都要通过遍历一遍询问来得到答案,所以时间复杂度是O(NMlogN), !

    相关 [笔记]分治

    基本思路:点分治,是一种针对可带权树上简单路径统计问题的算法。对于一个节点,只解决经过这棵子树的根节点的路径,对于子节点问题下推子树。 //当初的主要问题是vis[]