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

第三题:数的重心;poj1655

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

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=2e4+;
template<typename T>inline void read(T &x)
{
x=;
T f=,ch=getchar();
while (!isdigit(ch) && ch^'-') f=-, ch=getchar();
if (ch=='-') f=-, ch=getchar();
while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
x*=f;
}
int vis[maxn],siz[maxn],ans,pos,n;
int ver[maxn<<],Next[maxn<<],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
inline void dfs(int x)
{
vis[x]=,siz[x]=;
int maxpart=;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i];
if (!vis[y])
{
dfs(y);
siz[x]+=siz[y];
maxpart=max(maxpart,siz[y]);
}
}
maxpart=max(maxpart,n-siz[x]);
if (maxpart<ans || (maxpart==ans && x<pos))
ans=maxpart,pos=x;
}
int main()
{
int t;read(t);
while (t--)
{
read(n);
memset(vis,,sizeof(vis));
memset(head,,sizeof(head));
len=pos=;
ans=0x3f3f3f3f;
for (int x,y,i=;i<n;++i)
{
read(x);read(y);
add(x,y);add(y,x);
}
dfs();
printf("%d %d\n",pos,ans);
}
return ;
}

我写的邻接矩阵

#include<algorithm>
#include<bitset>
#include<cctype>
#include<cerrno>
#include<clocale>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<limits>
#include<list>
#include<map>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<utility>
#include<vector>
#include<cwchar>
#include<cwctype>
using namespace std;
const int maxn=2e4+;
const int INF=0x3f3f3f3f;
vector<int>G[maxn];
int son[maxn];
int ans,n,balance,t; void dfs(int v,int fa)
{
son[v]=;
int d=G[v].size();
int pre_balance=;
for (int i=;i<d;i++)
{
int k=G[v][i];
if (k!=fa)
{
dfs(k,v);
son[v]+=son[k];
pre_balance=max(pre_balance,son[k]);
}
}
pre_balance=max(pre_balance,n-son[v]);
if (pre_balance<balance || (pre_balance==balance&&v<ans))
{
ans=v;
balance=pre_balance;
}
}
int main()
{
cin>>t;
while (t--)
{
scanf("%d",&n);
for (int i=;i<=n;++i)
G[i].clear();
for (int i=;i<n;i++)
{
int s,e;
scanf("%d%d",&s,&e);
G[s].push_back(e);
G[e].push_back(s);
}
memset(son,,sizeof(son));
ans=;balance=INF;
dfs(,);
cout<<ans<<' '<<balance<<endl;
}
return ;
}

Noip 2018 旅行;luogu5022

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

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

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

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

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

#include <algorithm>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <iomanip>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define R register
using namespace std;
typedef long long ull;
const int maxn = 5e3 + ; inline int read() {
int s = , w = ;
char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -; ch = getchar(); }
while (isdigit(ch)) { s = (s << ) + (s << ) + (ch ^ ); ch = getchar(); }
return s * w;
} inline void write(int x)
{
if(x < ) putchar('-'),x = -x;
if(x > ) write(x / );
putchar(x % + '');
} vector <int> vec[maxn];
int ans[maxn], edge[maxn][], t[maxn], vis[maxn];
int n, m, da, db, tsize = ; inline void dfs(int x) {
t[++tsize] = x; vis[x] = ;
int l = vec[x].size();
for (R int i = ; i < l; ++i) {
int y = vec[x][i];
if (!vis[y] && !((x == da && y == db) || (x == db && y == da))) dfs(y);
}
return ;
} inline void check() {
if (tsize != n) return ;
for (R int i = ; i <= n; ++i) {
if (t[i] != ans[i]) {
if (t[i] > ans[i]) return ;
break;
}
}
for (R int i = ; i <= n; ++i) {
ans[i] = t[i];
}
return ;
} int main() {
memset(ans, 0x3f, sizeof(ans));
n = read(), m = read();
for (R int i = ; i <= m; ++i) {
int a = read(), b = read();
vec[a].push_back(b);
vec[b].push_back(a);
edge[i][] = a;
edge[i][] = b;
}
for (R int i = ; i <= n; ++i) sort(vec[i].begin(), vec[i].end());
if (n > m) {
da = -, db = -;
dfs();
check();
}
else {
for (R int i = ; i <= m; ++i) {
tsize = ;
da = edge[i][];
db = edge[i][];
memset(vis, , sizeof(vis));
dfs();
check();
}
}
for (R int i = ; i <= n; ++i) write(ans[i]), putchar(' ');
return ;
}

第四题:BZOJ 1791

跑一个基环树直径;

来自石神的模板;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+;
template<typename T>inline void read(T &x)
{
x=;
T f=,ch=getchar();
while (!isdigit(ch)) ch=getchar();
if (ch=='-') f=-, ch=getchar();
while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
x*=f;
}
int n,m,t;//t是标识符
int ver[maxn<<],edge[maxn<<],next[maxn<<],head[maxn],tot,du[maxn];
void add(int x,int y,int z)
{
ver[++tot]=y,edge[tot]=z,next[tot]=head[x],head[x]=tot,++du[y];
}
int c[maxn];//环上的点
int v[maxn];
int q[maxn<<];
void bfs(int s,int t)
{
int l,r;
q[l=r=]=s;//手写队列维护
c[s]=t;//标记连通块(看每个节点属于哪个基环树)
while (l<=r)
{
for (int i=head[q[l]]; i; i=next[i])
if (!c[ver[i]])
{
q[++r]=ver[i];
c[ver[i]]=t;
}
l++;
}
}
ll f[maxn];//每颗子树的直径
ll d[maxn];//每个节点的子树大小
void topsort()//找环操作顺便处理一种情况(直径不经过环)
{
int l=,r=,x,y;
for (int i=; i<=n; ++i)
if (du[i]==)//无向图度数为1
q[++r]=i;
while (l<=r)
{
for (int i=head[x=q[l]]; i; i=next[i])
if (du[y=ver[i]]>)//度大于1可更新答案
{
d[c[x]]=max(d[c[x]],f[x]+f[y]+edge[i]);//子树内最长链
f[y]=max(f[y],f[x]+edge[i]);//f[x]表示x子树中离x最远的点的距离
if ((--du[y])==)
q[++r]=y;
}
l++;
}
}
ll a[maxn<<];
ll b[maxn<<];
void dp(int t,int x)
{
int m=,i,l=,r,y=x;
do
{
a[++m]=f[y];
du[y]=;
for (i=head[y]; i; i=next[i])
if (du[ver[i]]>)//点在环上
{
y=ver[i];
b[m+]=b[m]+edge[i];//b[i]表示环上x到i的距离
break;
}
} while (i);//此时答案为 f[i]+f[j]+dis[i][j]的最大值,dis[i][j]表示环上i到j的最远距离
if (m==)//跑到环外,需要特判
{
for (i=head[y]; i; i=next[i])
if (ver[i]==x)
l=max(l,edge[i]);
d[t]=max(d[t],f[x]+f[y]+l);
return;
}
for (i=head[y]; i; i=next[i])//连接环的首尾
if (ver[i]==x)
{
b[m+]=b[m]+edge[i];
break;
}
for (i=; i<m; ++i)//由于是环,所以复制一份
{
a[m+i]=a[i];
b[m+i]=b[m+]+b[i];
}
q[l=r=]=;
for (i=; i<*m; ++i)
{
while (l<=r && i-q[l]>=m) ++l;
d[t]=max(d[t],a[i]+a[q[l]]+b[i]-b[q[l]]);
while (l<=r && a[q[r]]+b[i]-b[q[r]]<=a[i]) --r;//单调队列维护
q[++r]=i;
}
}
int main()
{
read(n);
for (int i=; i<=n; ++i)
{
int x,y;
read(x);read(y);
add(i,x,y),add(x,i,y);
}
for (int i=; i<=n; ++i)
if (!c[i])
bfs(i,++t);//统计有多少基环树
topsort();//拓扑找环 memset(v,,sizeof(v));//重新利用v数组,当作基环树是否算过
ll ans=0ll;
for (int i=; i<=n; ++i)
if (du[i]> && !v[c[i]])//每个基环树只跑一遍并且此时i是环上一点
{
v[c[i]]=;
dp(c[i],i);//求基环树的直径
ans+=d[c[i]];
}
printf("%lld\n",ans);
return ;
}

第五题: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]。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5e2;
template<typename T>inline void read(T &x)
{
x=;
T f=,ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-, ch=getchar();
while (isdigit(ch)) x=(x<<)+(x<<)+(ch^), ch=getchar();
x*=f;
}
int ver[maxn<<],Next[maxn<<],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int n,power[maxn],hate[maxn],vis[maxn],U,V;
ll f[maxn],g[maxn];
inline void dfs(int x,int fa)//dfs找环
{
vis[x]=;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i];
if (y!=fa)
{
if (!vis[y]) dfs(y,x);
else
{
vis[y]=;
U=x,V=y;
return ;
}
}
}
}
inline void tree_dp(int x,int fa,int rt,int ban)//ban 不选的点
{
vis[x]=;
f[x]=power[x];
g[x]=;
for (int i=head[x];i;i=Next[i])
{
int y=ver[i];
if (x==rt && i==ban) continue;
if (y!=fa && y!=rt)
{
tree_dp(y,x,rt,ban);
f[x]+=g[y];
g[x]+=max(g[y],f[y]);
}
}
}
int main()
{
read(n);
for (int i=,k;i<=n;++i)
{
read(power[i]);read(hate[i]);
add(i,hate[i]),add(hate[i],i);
}
ll ans=;
for (int i=;i<=n;++i)
if (!vis[i])
{
dfs(i,-);
int banu,banv;
for (int i=head[U];i;i=Next[i])
if (ver[i]==V)
{
banu=i;
break;
}
for (int i=head[V];i;i=Next[i])
if (ver[i]==U)
{
banv=i;
break;
}
tree_dp(U,-,U,banu);//断环为链并将断开的两个点强制其中一个点为根且不选,做一次树形DP
ll uans=g[U];
tree_dp(V,-,V,banv);//对另一个点做同样操作
ll vans=g[V];
ans+=max(uans,vans);//取两次结果最大值加入ans
}
printf("%lld\n",ans);
return ;
}

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. Android 7.0 适配

    extends:http://www.jianshu.com/p/56b9fb319310http://blog.csdn.net/chay_chan/article/details/57083383

  2. CentOS 7.0关闭服务器的防火墙服务命令

    1.直接关闭防火墙systemctl stop firewalld.service #停止firewallsystemctl disable firewalld.service #禁止firewall ...

  3. plsql中文乱码

    一.关于PLSQL无法正确显示中文 刚才下载安装了PLSQL Developer 9.0.0.1601 汉化绿色版,执行SQL查询语句,发现显示的数据中只要有中文都会以?表示. 原因:客户端跟服务器的 ...

  4. 用TreeSet生成不重复自动排序随机数组

    随机数组就是在指定长度的数组中用随机数字为每个元素赋值,常用于不确定数值的环境,如拼图游戏需要随机数组来打乱图片顺序.可是同时也存在问题,就是随机数的重复问题,这个问题常常被忽略. TreeSet类的 ...

  5. 怎么在Centos7 下让我的mariadb开机启动?(已解决)

    以前我经常使用syscemctl工具在开机后执行 systemctl start mariadb (哈哈,打得可6,只是有点儿麻烦), 如果能开机自启动mariadb就好了. 所以,我想百度下看什么命 ...

  6. 找不到 main 方法, 请将 main 方法定义为: public static void main(String[] args) 否则 JavaFX 应用程序类必须扩展javafx.应用程序类必 须扩展javafx.application.Application”

    用eclipse写代码的时候,写了一个简单的程序,编译的时候突然出现“错误: 在类 com.test.demo 中找不到 main 方法, 请将 main 方法定义为: public static v ...

  7. DataGrid表格某单元格数据填入是否正确的验证---MiniUI使用

    示例: <div id="datagrid1" class="mini-datagrid" oncellvalidation="onCellVa ...

  8. Changing Ethernet Media Speed for AIX

    ITS UNIX Systems Changing Ethernet Media Speed for AIX First you need to find out the device name of ...

  9. freeswitch的拨号规则配置

    当一个呼叫在ROUTING状态下达到命中拨号规则解析器时,相应的拨号规则就开始解析了.随着解析的进行,在xml文件中的符合条件的或标签中的指令形成一个指令表,安装到这个通道中. 你可以将拨号规则文件放 ...

  10. Kafka— —副本(均衡负载)

    创建一个副本数为3的topic Now create a new topic with a replication factor of three: > bin/kafka-topics.sh ...