博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树形结构升级
阅读量:5344 次
发布时间:2019-06-15

本文共 3020 字,大约阅读时间需要 10 分钟。

(以下默认 \(n\le 10^5\)

C Codeforces 191C

给你一棵树,有 \(k\) 对节点,问每条边有多少对节点的路径经过。

树上差分搞一搞。(从下往上)

D BZOJ 3124

求一棵树直径长度、有多少条边满足所有的直径都经过该边。

求直径好办。

第二问中,在直径上按顺序访问(我们假设是从左到右)每一个节点做一遍dfs,如果搜到某个节点到当前节点的距离等于当前节点到直径 左 端点的距离,那么该节点左边的所有边一定不满足题意。
如果搜到某个节点到当前节点的距离等于当前节点到直径 右 端点的距离,那么break;

E Codeforces 734E

一棵树,每个节点有黑、白两色。

现在可以进行若干次操作,每次选定一个节点,可以将所有满足条件的节点涂成与该节点相同的颜色:选定的节点与该节点的路径上所有节点的颜色都与该节点相同。
问最少几步能将整棵树涂成同一种颜色。

初始时和每次操作后将颜色相同且相邻的节点缩成一点(需使用并查集),然后建一棵缩点后的新树,然后求出该树的直径,答案为 \((直径+1)/2\)

方法是不停地更改一个节点的颜色。

F Codeforces 379F

给你一棵树,初始时长这样

1516397-20190303153419642-1888080657.png

然后进行 \(n\) 次操作,每次选定一个节点,在它下面增加两个子节点,并询问当前树的直径。

每增加一个节点就检查它到直径两个端点的距离是否大于当前直径长度,如果大于,更新当前直径的一个端点。

两节点的距离用lca解决。

G Codeforces 294E

有一棵树,现在你要删除一条边,然后增加一条边权与删除的边的边权相等的边,需保证树依然连通,并最小化两两节点的距离和。输出这个距离和。

\((2 ≤ n ≤ 5000)\)

先枚举每一条边作为删除的边,然后计算答案。

新建的边一定建在删边之后形成的两颗子树的重心之间。
然后运用加法原理+乘法原理dp一下。(有点复杂)(注意别忘开long long

Code

#include
#define maxn 5003#define INF 100000000000000000llusing namespace std;struct edge{ int to,next,w;}e[maxn<<1];int head[maxn],cnte,dep[maxn];void add(int u,int v,int w){ e[++cnte].to=v; e[cnte].w=w; e[cnte].next=head[u]; head[u]=cnte;}int n,G,sz[maxn];long long sumw[maxn],answ[maxn],sumG;void solve(int u,int last){ sz[u]=1; sumw[u]=0; answ[u]=0; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v==last)continue; solve(v,u); answ[u]+=answ[v]+sumw[v]*sz[u]+sumw[u]*sz[v]+(long long)sz[u]*sz[v]*e[i].w; sumw[u]+=sumw[v]+(long long)e[i].w*sz[v]; sz[u]+=sz[v]; }}void dfs(int u,int last,int totsz){ sumG=min(sumG,sumw[u]); for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(v==last)continue; sumw[v]=sumw[u]+(long long)(totsz-sz[v]-sz[v])*e[i].w; dfs(v,u,totsz); }}int main(){ scanf("%d",&n); for(int i=1;i

H BZOJ 1977

求一张无向图的严格次小生成树的边权和。

先用Kruskal求出最小生成树(MST)。

然后对于每一条未加入的边,算出该边的两个节点在MST中路径上的最大值和次大值(需要用到倍增及其预处理)。
可以证明,这个最大值一定 \(\le\) 该边边权。
如果最大值等于边权,那么用边权更新次大值;否则用边权更新最大值。

I ZOJ 3649

有一颗树,有点权,记为 \(a_i\) ,有若干询问,每个询问有 \(u,v\) 两个数,问在 \(u,v\) 之间的节点路径序列上,最大的 \(a_k-a_j(c_k≥c_j,j\le k)\) 是多少。

倍增处理四个值:(以下 \(dep\) 为深度数组)

\(A_u=\max\{a_i\}(i在路径(u,1)上)\)
\(B_u=\min\{a_i\}(i在路径(u,1)上)\)
\(C_u=\max\{a_i-a_j\}(i,j在路径(u,1)上,dep[i]<dep[j])\)
\(D_u=\max\{a_i-a_j\}(i,j在路径(u,1)上,dep[i]>dep[j])\)

每次查询两个节点 \(x,y\) 时,我们令 \(x\) 所在的链为左链, \(y\) 所在的链为右链,答案为\(\max\{C_x,D_y,A_y-B_x,A_j-B_i,A_l-B_k\}(i,j在左链上,dep[j]<dep[i];k,l在右链上,dep[l]>dep[k])\)

J hdu 4582

给你一张图及其dfs生成树,问最少选择多少条边,使得图中所有的简单环(只有一条边不在dfs生成树内)至少包含一条已选择的边。

当是一条链的情况时,对所有右端点排序,然后每次贪心选最左边的右端点所在的边。

当时一棵树的情况时,按深度从大到小排序即可。

K poj 1144

给你一张无向图,求割边数量。

模板题

L ZOJ 2588

给你一张无向图,输出所有割边。

同上

M hdu 1007

求平面上的最近点对。

分治。

按横坐标将所有节点排序,每次取一个mid,然后左、右区间分治,合并时统计分治上来的答案 \(d\)
我们做一条直线 \(x=x_mid\) ,然后找出在直线 \(x=x_mid-d\)\(x=x_mid+d\) 中间的点,暴力统计这些点的答案。
算法导论中有证明,刚刚的这些点个数不会超过 \(8\) 个。

N hdu 4822

给定一棵树,和树上节点 \(A,B,C\) ,若节点 \(X\) 到节点 \(A\) 的距离严格小于到 \(B,C\) 的距离,那么称 \(X\)\(A\) 占有。有若干询问,每次给定一组 \(A,B,C\) ,问各占领的节点数。

\(\color{white}{码力过大~~~}\)

转载于:https://www.cnblogs.com/BlogOfchc1234567890/p/10466112.html

你可能感兴趣的文章
$ 一步一步学Matlab(3)——Matlab中的数据类型
查看>>
5.6.3.7 localeCompare() 方法
查看>>
Linux下好用的简单实用命令
查看>>
常用web字体的使用指南
查看>>
描绘应用程序级的信息
查看>>
poj2406-Power Strings
查看>>
2018/12/18 JS会像Linux一样改变编程
查看>>
php环境搭建脚本
查看>>
FTP主动模式与被动模式说明
查看>>
php 编译常见错误
查看>>
MES架构
查看>>
【Python3 爬虫】15_Fiddler抓包分析
查看>>
高性能JavaScript-JS脚本加载与执行对性能的影响
查看>>
关于标签之间因为换行等问题造成的空白间距问题处理
查看>>
hdu 2767(tarjan)
查看>>
sklearn之分类模型混淆矩阵和分类报告
查看>>
MySQL各存储引擎
查看>>
项目--简单导出CSV文件
查看>>
Oracle session相关数据字典(一)
查看>>
织梦文章内容提取第一张或者多张图片输出
查看>>