第一题第二题鉴上我前几篇博客poj1985 poj1849https://www.cnblogs.com/Tyouchie/p/10384379.html

第三题:数的重心;poj1655

来自sjh大佬的版子,邻接表写法

  1. #include<algorithm>
  2. #include<bitset>
  3. #include<cctype>
  4. #include<cerrno>
  5. #include<clocale>
  6. #include<cmath>
  7. #include<complex>
  8. #include<cstdio>
  9. #include<cstdlib>
  10. #include<cstring>
  11. #include<ctime>
  12. #include<deque>
  13. #include<exception>
  14. #include<fstream>
  15. #include<functional>
  16. #include<limits>
  17. #include<list>
  18. #include<map>
  19. #include<iomanip>
  20. #include<ios>
  21. #include<iosfwd>
  22. #include<iostream>
  23. #include<istream>
  24. #include<ostream>
  25. #include<queue>
  26. #include<set>
  27. #include<sstream>
  28. #include<stack>
  29. #include<stdexcept>
  30. #include<streambuf>
  31. #include<string>
  32. #include<utility>
  33. #include<vector>
  34. #include<cwchar>
  35. #include<cwctype>
  36. using namespace std;
  37. const int maxn=2e4+;
  38. template<typename T>inline void read(T &x)
  39. {
  40. x=;
  41. T f=,ch=getchar();
  42. while (!isdigit(ch) && ch^'-') f=-, ch=getchar();
  43. if (ch=='-') f=-, ch=getchar();
  44. while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
  45. x*=f;
  46. }
  47. int vis[maxn],siz[maxn],ans,pos,n;
  48. int ver[maxn<<],Next[maxn<<],head[maxn],len;
  49. inline void add(int x,int y)
  50. {
  51. ver[++len]=y,Next[len]=head[x],head[x]=len;
  52. }
  53. inline void dfs(int x)
  54. {
  55. vis[x]=,siz[x]=;
  56. int maxpart=;
  57. for (int i=head[x];i;i=Next[i])
  58. {
  59. int y=ver[i];
  60. if (!vis[y])
  61. {
  62. dfs(y);
  63. siz[x]+=siz[y];
  64. maxpart=max(maxpart,siz[y]);
  65. }
  66. }
  67. maxpart=max(maxpart,n-siz[x]);
  68. if (maxpart<ans || (maxpart==ans && x<pos))
  69. ans=maxpart,pos=x;
  70. }
  71. int main()
  72. {
  73. int t;read(t);
  74. while (t--)
  75. {
  76. read(n);
  77. memset(vis,,sizeof(vis));
  78. memset(head,,sizeof(head));
  79. len=pos=;
  80. ans=0x3f3f3f3f;
  81. for (int x,y,i=;i<n;++i)
  82. {
  83. read(x);read(y);
  84. add(x,y);add(y,x);
  85. }
  86. dfs();
  87. printf("%d %d\n",pos,ans);
  88. }
  89. return ;
  90. }

我写的邻接矩阵

  1. #include<algorithm>
  2. #include<bitset>
  3. #include<cctype>
  4. #include<cerrno>
  5. #include<clocale>
  6. #include<cmath>
  7. #include<complex>
  8. #include<cstdio>
  9. #include<cstdlib>
  10. #include<cstring>
  11. #include<ctime>
  12. #include<deque>
  13. #include<exception>
  14. #include<fstream>
  15. #include<functional>
  16. #include<limits>
  17. #include<list>
  18. #include<map>
  19. #include<iomanip>
  20. #include<ios>
  21. #include<iosfwd>
  22. #include<iostream>
  23. #include<istream>
  24. #include<ostream>
  25. #include<queue>
  26. #include<set>
  27. #include<sstream>
  28. #include<stack>
  29. #include<stdexcept>
  30. #include<streambuf>
  31. #include<string>
  32. #include<utility>
  33. #include<vector>
  34. #include<cwchar>
  35. #include<cwctype>
  36. using namespace std;
  37. const int maxn=2e4+;
  38. const int INF=0x3f3f3f3f;
  39. vector<int>G[maxn];
  40. int son[maxn];
  41. int ans,n,balance,t;
  42.  
  43. void dfs(int v,int fa)
  44. {
  45. son[v]=;
  46. int d=G[v].size();
  47. int pre_balance=;
  48. for (int i=;i<d;i++)
  49. {
  50. int k=G[v][i];
  51. if (k!=fa)
  52. {
  53. dfs(k,v);
  54. son[v]+=son[k];
  55. pre_balance=max(pre_balance,son[k]);
  56. }
  57. }
  58. pre_balance=max(pre_balance,n-son[v]);
  59. if (pre_balance<balance || (pre_balance==balance&&v<ans))
  60. {
  61. ans=v;
  62. balance=pre_balance;
  63. }
  64. }
  65. int main()
  66. {
  67. cin>>t;
  68. while (t--)
  69. {
  70. scanf("%d",&n);
  71. for (int i=;i<=n;++i)
  72. G[i].clear();
  73. for (int i=;i<n;i++)
  74. {
  75. int s,e;
  76. scanf("%d%d",&s,&e);
  77. G[s].push_back(e);
  78. G[e].push_back(s);
  79. }
  80. memset(son,,sizeof(son));
  81. ans=;balance=INF;
  82. dfs(,);
  83. cout<<ans<<' '<<balance<<endl;
  84. }
  85. return ;
  86. }

Noip 2018 旅行;luogu5022

题意:一个n个点,m条边的连通图。可以从任意一个点出发,前往任意 一个相邻的未访问的结点,或沿着上一次来这个点的边返回。需要遍历 每一个点。每经过一个新的结点,就将这个结点写下来。最终可以得到 一个序列。求字典序最小的序列。 n ≤ 5000, m ≤ n。

貌似用栈慢一点,洛谷最后一个点过不了,要用02优化;

但是用栈维护单调性比较方便;

n < m:对于树的情况,显然从1出发,每次从字典序最小的相邻结 点DFS即可。

n = m: 对于有环的情况,由于环只有一个,我们可以将环找出来, 枚举删掉环上的每一条边,然后按树的情况求解即可。 时间复杂度O(n 2 )。

  1. #include <algorithm>
  2. #include <cctype>
  3. #include <cmath>
  4. #include <complex>
  5. #include <cstdio>
  6. #include <cstring>
  7. #include <deque>
  8. #include <functional>
  9. #include <list>
  10. #include <map>
  11. #include <iomanip>
  12. #include <iostream>
  13. #include <queue>
  14. #include <set>
  15. #include <stack>
  16. #include <string>
  17. #include <vector>
  18. #define R register
  19. using namespace std;
  20. typedef long long ull;
  21. const int maxn = 5e3 + ;
  22.  
  23. inline int read() {
  24. int s = , w = ;
  25. char ch = getchar();
  26. while (!isdigit(ch)) { if (ch == '-') w = -; ch = getchar(); }
  27. while (isdigit(ch)) { s = (s << ) + (s << ) + (ch ^ ); ch = getchar(); }
  28. return s * w;
  29. }
  30.  
  31. inline void write(int x)
  32. {
  33. if(x < ) putchar('-'),x = -x;
  34. if(x > ) write(x / );
  35. putchar(x % + '');
  36. }
  37.  
  38. vector <int> vec[maxn];
  39. int ans[maxn], edge[maxn][], t[maxn], vis[maxn];
  40. int n, m, da, db, tsize = ;
  41.  
  42. inline void dfs(int x) {
  43. t[++tsize] = x; vis[x] = ;
  44. int l = vec[x].size();
  45. for (R int i = ; i < l; ++i) {
  46. int y = vec[x][i];
  47. if (!vis[y] && !((x == da && y == db) || (x == db && y == da))) dfs(y);
  48. }
  49. return ;
  50. }
  51.  
  52. inline void check() {
  53. if (tsize != n) return ;
  54. for (R int i = ; i <= n; ++i) {
  55. if (t[i] != ans[i]) {
  56. if (t[i] > ans[i]) return ;
  57. break;
  58. }
  59. }
  60. for (R int i = ; i <= n; ++i) {
  61. ans[i] = t[i];
  62. }
  63. return ;
  64. }
  65.  
  66. int main() {
  67. memset(ans, 0x3f, sizeof(ans));
  68. n = read(), m = read();
  69. for (R int i = ; i <= m; ++i) {
  70. int a = read(), b = read();
  71. vec[a].push_back(b);
  72. vec[b].push_back(a);
  73. edge[i][] = a;
  74. edge[i][] = b;
  75. }
  76. for (R int i = ; i <= n; ++i) sort(vec[i].begin(), vec[i].end());
  77. if (n > m) {
  78. da = -, db = -;
  79. dfs();
  80. check();
  81. }
  82. else {
  83. for (R int i = ; i <= m; ++i) {
  84. tsize = ;
  85. da = edge[i][];
  86. db = edge[i][];
  87. memset(vis, , sizeof(vis));
  88. dfs();
  89. check();
  90. }
  91. }
  92. for (R int i = ; i <= n; ++i) write(ans[i]), putchar(' ');
  93. return ;
  94. }

第四题:BZOJ 1791

跑一个基环树直径;

来自石神的模板;

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn=1e6+;
  5. template<typename T>inline void read(T &x)
  6. {
  7. x=;
  8. T f=,ch=getchar();
  9. while (!isdigit(ch)) ch=getchar();
  10. if (ch=='-') f=-, ch=getchar();
  11. while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
  12. x*=f;
  13. }
  14. int n,m,t;//t是标识符
  15. int ver[maxn<<],edge[maxn<<],next[maxn<<],head[maxn],tot,du[maxn];
  16. void add(int x,int y,int z)
  17. {
  18. ver[++tot]=y,edge[tot]=z,next[tot]=head[x],head[x]=tot,++du[y];
  19. }
  20. int c[maxn];//环上的点
  21. int v[maxn];
  22. int q[maxn<<];
  23. void bfs(int s,int t)
  24. {
  25. int l,r;
  26. q[l=r=]=s;//手写队列维护
  27. c[s]=t;//标记连通块(看每个节点属于哪个基环树)
  28. while (l<=r)
  29. {
  30. for (int i=head[q[l]]; i; i=next[i])
  31. if (!c[ver[i]])
  32. {
  33. q[++r]=ver[i];
  34. c[ver[i]]=t;
  35. }
  36. l++;
  37. }
  38. }
  39. ll f[maxn];//每颗子树的直径
  40. ll d[maxn];//每个节点的子树大小
  41. void topsort()//找环操作顺便处理一种情况(直径不经过环)
  42. {
  43. int l=,r=,x,y;
  44. for (int i=; i<=n; ++i)
  45. if (du[i]==)//无向图度数为1
  46. q[++r]=i;
  47. while (l<=r)
  48. {
  49. for (int i=head[x=q[l]]; i; i=next[i])
  50. if (du[y=ver[i]]>)//度大于1可更新答案
  51. {
  52. d[c[x]]=max(d[c[x]],f[x]+f[y]+edge[i]);//子树内最长链
  53. f[y]=max(f[y],f[x]+edge[i]);//f[x]表示x子树中离x最远的点的距离
  54. if ((--du[y])==)
  55. q[++r]=y;
  56. }
  57. l++;
  58. }
  59. }
  60. ll a[maxn<<];
  61. ll b[maxn<<];
  62. void dp(int t,int x)
  63. {
  64. int m=,i,l=,r,y=x;
  65. do
  66. {
  67. a[++m]=f[y];
  68. du[y]=;
  69. for (i=head[y]; i; i=next[i])
  70. if (du[ver[i]]>)//点在环上
  71. {
  72. y=ver[i];
  73. b[m+]=b[m]+edge[i];//b[i]表示环上x到i的距离
  74. break;
  75. }
  76. } while (i);//此时答案为 f[i]+f[j]+dis[i][j]的最大值,dis[i][j]表示环上i到j的最远距离
  77. if (m==)//跑到环外,需要特判
  78. {
  79. for (i=head[y]; i; i=next[i])
  80. if (ver[i]==x)
  81. l=max(l,edge[i]);
  82. d[t]=max(d[t],f[x]+f[y]+l);
  83. return;
  84. }
  85. for (i=head[y]; i; i=next[i])//连接环的首尾
  86. if (ver[i]==x)
  87. {
  88. b[m+]=b[m]+edge[i];
  89. break;
  90. }
  91. for (i=; i<m; ++i)//由于是环,所以复制一份
  92. {
  93. a[m+i]=a[i];
  94. b[m+i]=b[m+]+b[i];
  95. }
  96. q[l=r=]=;
  97. for (i=; i<*m; ++i)
  98. {
  99. while (l<=r && i-q[l]>=m) ++l;
  100. d[t]=max(d[t],a[i]+a[q[l]]+b[i]-b[q[l]]);
  101. while (l<=r && a[q[r]]+b[i]-b[q[r]]<=a[i]) --r;//单调队列维护
  102. q[++r]=i;
  103. }
  104. }
  105. int main()
  106. {
  107. read(n);
  108. for (int i=; i<=n; ++i)
  109. {
  110. int x,y;
  111. read(x);read(y);
  112. add(i,x,y),add(x,i,y);
  113. }
  114. for (int i=; i<=n; ++i)
  115. if (!c[i])
  116. bfs(i,++t);//统计有多少基环树
  117. topsort();//拓扑找环
  118.  
  119. memset(v,,sizeof(v));//重新利用v数组,当作基环树是否算过
  120. ll ans=0ll;
  121. for (int i=; i<=n; ++i)
  122. if (du[i]> && !v[c[i]])//每个基环树只跑一遍并且此时i是环上一点
  123. {
  124. v[c[i]]=;
  125. dp(c[i],i);//求基环树的直径
  126. ans+=d[c[i]];
  127. }
  128. printf("%lld\n",ans);
  129. return ;
  130. }

第五题:LUOGU CF 835F

第六题“:BZOJ 1040

题意:n个点n条边的图,每个点都有点权,要求找到一个点集,点集中的 点相互之间不能有边相连,最大化点集的权值和。 1 ≤ n ≤ 106

如果联通的话,就是一个基环树了,否则为基环树森林。

这道题可 以简单的抽象为:基环树的最大独立集。

如果是一棵树该怎么做?

DP。

f [i][0] =∑max(f [son[i]][0], f [son[i][1])

f [i][1] =∑f [son[i]][0]

在每一棵基环树的环上枚举一条边,记它的两个端点为u和v,然后 删掉这条边做树形dp即可。

从该边的两个端点出发选择:

1 强制不选u,v任意,环的贡献为以u做DP的f [u][0]。

2 强制不选v,u任意,环的贡献为以v做DP的f [v][0]。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn=1e6+5e2;
  5. template<typename T>inline void read(T &x)
  6. {
  7. x=;
  8. T f=,ch=getchar();
  9. while (!isdigit(ch) && ch^'-') ch=getchar();
  10. if (ch=='-') f=-, ch=getchar();
  11. while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
  12. x*=f;
  13. }
  14. int ver[maxn<<],Next[maxn<<],head[maxn],len;
  15. inline void add(int x,int y)
  16. {
  17. ver[++len]=y,Next[len]=head[x],head[x]=len;
  18. }
  19. int n,power[maxn],hate[maxn],vis[maxn],U,V;
  20. ll f[maxn],g[maxn];
  21. inline void dfs(int x,int fa)//dfs找环
  22. {
  23. vis[x]=;
  24. for (int i=head[x];i;i=Next[i])
  25. {
  26. int y=ver[i];
  27. if (y!=fa)
  28. {
  29. if (!vis[y]) dfs(y,x);
  30. else
  31. {
  32. vis[y]=;
  33. U=x,V=y;
  34. return ;
  35. }
  36. }
  37. }
  38. }
  39. inline void tree_dp(int x,int fa,int rt,int ban)//ban 不选的点
  40. {
  41. vis[x]=;
  42. f[x]=power[x];
  43. g[x]=;
  44. for (int i=head[x];i;i=Next[i])
  45. {
  46. int y=ver[i];
  47. if (x==rt && i==ban) continue;
  48. if (y!=fa && y!=rt)
  49. {
  50. tree_dp(y,x,rt,ban);
  51. f[x]+=g[y];
  52. g[x]+=max(g[y],f[y]);
  53. }
  54. }
  55. }
  56. int main()
  57. {
  58. read(n);
  59. for (int i=,k;i<=n;++i)
  60. {
  61. read(power[i]);read(hate[i]);
  62. add(i,hate[i]),add(hate[i],i);
  63. }
  64. ll ans=;
  65. for (int i=;i<=n;++i)
  66. if (!vis[i])
  67. {
  68. dfs(i,-);
  69. int banu,banv;
  70. for (int i=head[U];i;i=Next[i])
  71. if (ver[i]==V)
  72. {
  73. banu=i;
  74. break;
  75. }
  76. for (int i=head[V];i;i=Next[i])
  77. if (ver[i]==U)
  78. {
  79. banv=i;
  80. break;
  81. }
  82. tree_dp(U,-,U,banu);//断环为链并将断开的两个点强制其中一个点为根且不选,做一次树形DP
  83. ll uans=g[U];
  84. tree_dp(V,-,V,banv);//对另一个点做同样操作
  85. ll vans=g[V];
  86. ans+=max(uans,vans);//取两次结果最大值加入ans
  87. }
  88. printf("%lld\n",ans);
  89. return ;
  90. }

D4 树的直径、重心以及基环树的更多相关文章

  1. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  2. 『Island 基环树直径』

    Island(IOI 2008) Description 你准备浏览一个公园,该公园由 N 个岛屿组成,当地管理部门从每个岛屿 i 出发向另外一个岛屿建了一座长度为 L_i 的桥,不过桥是可以双向行走 ...

  3. BZOJ 1791: [IOI2008]Island 岛屿 - 基环树

    传送门 题解 题意 = 找出无向基环树森林的每颗基环树的直径. 我们首先需要找到每颗基环树的环, 但是因为是无向图,用tarjan找环, 加个手工栈, 我也是看了dalao的博客才知道tarjan找无 ...

  4. [IOI2008/BZOJ1791 岛屿](处理基环树的小技巧&基于bfs树形DP)

    IOI2008/BZOJ1791 岛屿 题目大意是在一个基环树森林里求每一棵基环树的直径①的和. 其实就是树的直径的基环树升级版.我们先把环找出来,然后从环上的每一个节点x出发,并且不经过环上其他节点 ...

  5. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  6. codeforces GYM 100114 J. Computer Network tarjan 树的直径 缩点

    J. Computer Network Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Des ...

  7. HDU4607 - Park Visit(树的直径)

    题目大意 给定一颗树,要求走过其中连续的k个点,使得步数最少 题解 每条边要么经过两次,要么一次,因为我们的目标就是使得走一次的边尽量的多,这样就转换成求树的直径了,求树的直径我用的是两次dfs,先随 ...

  8. BZOJ 1040 骑士 基环树 树形DP

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1040 题目大意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫 ...

  9. [10.12模拟赛] 老大 (二分/树的直径/树形dp)

    [10.12模拟赛] 老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图), ...

随机推荐

  1. Ubuntu 安装mono

    Ubuntu 安装mono 我的系统:Ubuntu 16   Mono参考: http://www.mono-project.com/docs/getting-started/install/linu ...

  2. CentOS7.X安装LMMP环境Nginx+PHP+Mysql详解

    前言: 作为PHP开发者,我们常用的线上环境就是LNMP,合理的搭建也是必须掌握的技能,下面就利用源码的方式详细介绍下LNMP环境Nginx+PHP+Mysql的详细搭建步骤: 版本说明: Nginx ...

  3. geotrellis使用(四十二)将 Shp 文件转为 GeoJson

    前言 一个多月没有写博客了,今天尝试着动笔写点. 原因很多,最重要的原因是我转行了.是的,我离开了开发岗位,走向了开发的天敌-产品经理.虽然名义上是产品经理,但是干的事情也很杂,除了不写代码,其他的都 ...

  4. layui---表单验证

    使用layui,使用它的表单验证也是比不可少的,下面就来总结下: <!-- 不用form 用div也可以 --> <form class="layui-form" ...

  5. python根据字符串导入模块

    问题: path = "auth.my_auth.AUTH" # 根据path实例化AUTH类 解决: path = "auth.my_auth.AUTH" i ...

  6. poj 2074

    哎怎么说,感觉现在处理平面上点线的题已经比较熟练了. 这题就离散化然后搞个前缀和就没了. 准备开始进一步的自闭了. 下面是disguss的一些样例... 其实是我自己写错了个地方,本来能1A的. #i ...

  7. HttpClient学习记录-系列1(tutorial)

    1. HttpClient使用了facade模式,如何使用的? 2. HTTP protocol interceptors使用了Decorator模式,如何使用的? URIBuilder respon ...

  8. C#遍历枚举(Enum)值

    foreach (object o in Enum.GetValues(typeof(EmpType))) { Console.WriteLine("{0}:{1}", o, En ...

  9. python全栈开发 * 12 知识点汇总 * 180530

    12 知识点总结 装饰器进阶 ⼀. 通⽤装饰器的回顾1.开闭原则: 对增加功能开放. 对修改代码封闭2.装饰器的作⽤: 在不改变原有代码的基础上给⼀个函数增加功能3.通⽤装饰器的写法:def wrap ...

  10. java八大数据类型

    基本数据类型以值传递的方式进行传递,String以值传递的方式传递,其他的以地址的方式进行传递 分别是:byte  short  int  long  float  double char boole ...