长链剖分题表

长链剖分,类似于重链剖分(dsu on tree)的一种替代算法。最广泛的用法是优化与深度有关的树上DP,以及处理一些与点分治类似的问题。有一部分长链剖分题也可以用dsu on tree做,单复杂度往往会多一个log。

每个点找到高度最大的儿子作为自己的重儿子,连续的重儿子形成重链。可以发现,一个点到根要经过的重链最多为$O(\sqrt{n})$个。一个点的任意祖先所在链长都不小于这个点所在的链长,容易证明,当重儿子信息$O(1)$传递,轻儿子信息$O(轻儿子所在重链长度)$传递时,均摊到每个点的复杂度都是$O(1)$,总复杂度为$O(n)$。

 

例一:[BZOJ3252]树上“k取方格数”问题,选k个叶子使到根路径并权值和最大。

这里只是用到了长链剖分的思想优化。

考虑网络流,发现树上不存在退流,于是模拟贪心,不断找叶子到根的权值最大的路径,计入答案后将路径清零。

显然每次可以取一条权值最大的长链即可。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 7 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 8 typedef long long ll;
 9 using namespace std;
10 
11 const int N=200010;
12 ll ans,len[N];
13 int n,k,u,v,cnt,a[N],son[N],h[N],to[N],nxt[N];
14 priority_queue<ll>Q;
15 
16 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
17 
18 void dfs(int x){
19     For(i,x){
20         dfs(k=to[i]);
21         if (len[k]>len[son[x]]) son[x]=k;
22     }
23     len[x]=len[son[x]]+a[x];
24 }
25 
26 void dfs2(int x,int top){
27     if (x==top) Q.push(len[x]);
28     if (son[x]) dfs2(son[x],top);
29     For(i,x) if ((k=to[i])!=son[x]) dfs2(k,k);
30 }
31 
32 int main(){
33     freopen("bzoj3252.in","r",stdin);
34     freopen("bzoj3252.out","w",stdout);
35     scanf("%d%d",&n,&k);
36     rep(i,1,n) scanf("%d",&a[i]);
37     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v);
38     dfs(1); dfs2(1,1);
39     while (k && !Q.empty()) ans+=Q.top(),Q.pop(),k--;
40     printf("%lld\n",ans);
41     return 0;
42 }
BZOJ3252

 

例二:[CF1009F]对每个子树找到一个深度使该子树内该深度的点最多。

f[x][i]表示x的i级子孙个数,发现重儿子的结果可以直接利用,轻儿子可以线性合并。

用指针实现二维数组以节省空间。这是此类问题的经典模板。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 7 typedef long long ll;
 8 using namespace std;
 9 
10 const int N=1000010;
11 int n,u,v,len[N],ans[N],fa[N],son[N],tmp[N],*f[N],*id=tmp;
12 int cnt,h[N],nxt[N<<1],to[N<<1];
13 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
14 
15 void dfs(int x){
16     For(i,x) if ((k=to[i])!=fa[x]){
17         fa[k]=x; dfs(k);
18         if (len[k]>len[son[x]]) son[x]=k;
19     }
20     len[x]=len[son[x]]+1;
21 }
22 
23 void DP(int x){
24     f[x][0]=1;
25     if (son[x]) f[son[x]]=f[x]+1,DP(son[x]),ans[x]=ans[son[x]]+1;
26     For(i,x) if ((k=to[i])!=fa[x] && k!=son[x]){
27         f[k]=id; id+=len[k]; DP(k);
28         rep(j,1,len[k]){
29             f[x][j]+=f[k][j-1];
30             if (f[x][j]>f[x][ans[x]] || (f[x][j]==f[x][ans[x]] && j<ans[x])) ans[x]=j;
31         }
32     }
33     if (f[x][ans[x]]==1) ans[x]=0;
34 }
35 
36 int main(){
37     freopen("1009F.in","r",stdin);
38     freopen("1009F.out","w",stdout);
39     scanf("%d",&n);
40     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
41     dfs(1); f[1]=id; id+=len[1]; DP(1);
42     rep(i,1,n) printf("%d\n",ans[i]);
43     return 0;
44 }
CF1009F

 

 例三:[COGS2652]树上每个点有两个权值ai,bi,找一条长为m的路径使sum(a[i])/sum(b[i])最小。

分数规划后变成找一条长度为m的最小路径,同样f[x][i]表示x开始往下的长为i的链的最小权值和为多少。

转移与更新答案显然,注意由于重儿子转移过来有一个全部加a[x]的操作,于是给每个点记录一个增量就好了。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 7 typedef long long ll;
 8 using namespace std;
 9 
10 const int N=200010;
11 int n,m,u,v,len[N],fa[N],son[N],a[N],b[N];
12 double val[N],tmp[N],*f[N],*id=tmp,ans=1e18;
13 int cnt,h[N],nxt[N<<1],to[N<<1];
14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
15 
16 void dfs(int x){
17     For(i,x) if ((k=to[i])!=fa[x]){
18         fa[k]=x; dfs(k);
19         if (len[k]>len[son[x]]) son[x]=k;
20     }
21     len[x]=len[son[x]]+1;
22 }
23 
24 void DP(int x,double mid){
25     val[x]=a[x]-mid*b[x]; f[x][0]=0;
26     if (son[x]) f[son[x]]=f[x]+1,DP(son[x],mid),val[x]+=val[son[x]],f[x][0]-=val[son[x]];
27     For(i,x) if ((k=to[i])!=fa[x] && k!=son[x]){
28         f[k]=id; id+=len[k]; DP(k,mid);
29         rep(j,0,min(len[k]-1,m-1))
30             if (m-j-1<len[x]) ans=min(ans,f[k][j]+val[k]+f[x][m-j-1]+val[x]);
31         rep(j,0,min(len[k]-1,m-1))
32             f[x][j+1]=min(f[x][j+1],f[k][j]+val[k]-val[x]+a[x]-mid*b[x]);
33     }
34     if (m<len[x]) ans=min(ans,f[x][m]+val[x]);
35 }
36 
37 int main(){
38     freopen("cogs2652.in","r",stdin);
39     freopen("cogs2652.out","w",stdout);
40     scanf("%d%d",&n,&m); m--;
41     rep(i,1,n) scanf("%d",&a[i]);
42     rep(i,1,n) scanf("%d",&b[i]);
43     rep(i,1,n) ans=min(ans,1.*a[i]/b[i]);
44     if (m==-2 || !m){ printf("%.2lf\n",ans); return 0; }
45     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
46     dfs(1); double l=0,r=N;
47     while (r-l>1e-3){
48         double mid=(l+r)/2;
49         memset(tmp,0x7f,sizeof(tmp)); ans=1e18;
50         id=tmp; f[1]=id; id+=len[1]; DP(1,mid);
51         if (ans>=0) l=mid; else r=mid;
52     }
53     if (l>=200000) puts("-1"); else printf("%.2lf\n",l);
54     return 0;
55 }
COGS2652

 

例四:[BZOJ4543]一棵树中选3个点,两两距离相等,求方案数。

暴力DP方法加上长链剖分即可。

https://www.cnblogs.com/zhoushuyu/p/9468669.html

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 7 typedef long long ll;
 8 using namespace std;
 9 
10 const int N=100010;
11 ll ans;
12 int n,u,v,len[N],fa[N],son[N],tmp[N<<2],*f[N],*g[N],*id=tmp;
13 int cnt,h[N],nxt[N<<1],to[N<<1];
14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
15 
16 void dfs(int x){
17     For(i,x) if ((k=to[i])!=fa[x]){
18         fa[k]=x; dfs(k);
19         if (len[k]>len[son[x]]) son[x]=k;
20     }
21     len[x]=len[son[x]]+1;
22 }
23 
24 void DP(int x){
25     if (son[x]) f[son[x]]=f[x]+1,g[son[x]]=g[x]-1,DP(son[x]);
26     f[x][0]=1; ans+=g[x][0];
27     For(i,x) if ((k=to[i])!=fa[x] && k!=son[x]){
28         f[k]=id; id+=len[k]<<1; g[k]=id; id+=len[k]<<1; DP(k);
29         rep(j,0,len[k]-1){
30             if (j) ans+=f[x][j-1]*g[k][j];
31             ans+=g[x][j+1]*f[k][j];
32         }
33         rep(j,0,len[k]-1){
34             g[x][j+1]+=f[x][j+1]*f[k][j];
35             if (j) g[x][j-1]+=g[k][j];
36             f[x][j+1]+=f[k][j];
37         }
38     }
39 }
40 
41 int main(){
42     freopen("bzoj4543.in","r",stdin);
43     freopen("bzoj4543.out","w",stdout);
44     scanf("%d",&n);
45     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
46     dfs(1); f[1]=id; id+=len[1]<<1; g[1]=id; id+=len[1]<<1;
47     DP(1); printf("%lld\n",ans);
48     return 0;
49 }
BZOJ4543

 

例五:[BZOJ3653]谈笑风生

同样没有什么要说的,暴力统计以深度为下标的信息,用上长链剖分复杂度就有保证了。

注意我们长链剖分的时候无法记录前缀和,但可以记录后缀和,且后缀和也是可以DP直接转移的。

 1 #include<cstdio>
 2 #include<vector>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 7 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 8 typedef long long ll;
 9 using namespace std;
10 
11 const int N=300010;
12 int n,u,v,Q,dep[N],fa[N],son[N];
13 int cnt,len[N],sz[N],h[N],nxt[N<<1],to[N<<1];
14 ll ans[N],tmp[N],*f[N],*id=tmp;
15 struct P{ int x,y; };
16 vector<P>ve[N];
17 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
18 
19 void dfs(int x){
20     dep[x]=dep[fa[x]]+1; sz[x]=1;
21     For(i,x) if ((k=to[i])!=fa[x]){
22         fa[k]=x; dfs(k); sz[x]+=sz[k];
23         if (len[k]>len[son[x]]) son[x]=k;
24     }
25     len[x]=len[son[x]]+1;
26 }
27 
28 void DP(int x){
29     if (son[x]) f[son[x]]=f[x]+1,DP(son[x]),f[x][0]+=f[son[x]][0];
30     f[x][0]+=sz[x]-1;
31     For(i,x) if ((k=to[i])!=fa[x] && k!=son[x]){
32         f[k]=id; id+=len[k]; DP(k);
33         rep(j,0,len[k]-1) f[x][j+1]+=f[k][j];
34         f[x][0]+=f[k][0];
35     }
36     int ed=ve[x].size()-1;
37     rep(i,0,ed){
38         int k=ve[x][i].y,id=ve[x][i].x;
39         ans[id]+=1ll*(sz[x]-1)*min(dep[x]-1,k);
40         if (k>=len[x]-1) ans[id]+=f[x][0]-sz[x]+1;
41             else ans[id]+=f[x][0]-sz[x]+1-f[x][k+1];
42     }
43 }
44 
45 int main(){
46     freopen("bzoj3653.in","r",stdin);
47     freopen("bzoj3653.out","w",stdout);
48     scanf("%d%d",&n,&Q);
49     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
50     dfs(1);
51     rep(i,1,Q) scanf("%d%d",&u,&v),ve[u].push_back((P){i,v});
52     f[1]=id; id+=len[1]; DP(1);
53     rep(i,1,Q) printf("%lld\n",ans[i]);
54     return 0;
55 }
BZOJ3653

 

转载于:https://www.cnblogs.com/HocRiser/p/10416144.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/484138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流计算

一.概述 实时获取来自不同数据源的海量数据经过实时分析处理&#xff0c;或的有价值的信息&#xff0e; 1.数据的处理流程 静态数据:数据不会发生变化&#xff0c;如数据仓库中的数据&#xff1b;流数据:数据以大量&#xff0c;快速&#xff0e;时变的流形式持续到达&#xf…

SpringBoot集成Spring Security(二)注册 、密码加密、修改密码

SpringBoot集成Spring Security&#xff08;一&#xff09;登录注销 写在前面 上一节创建了项目并且利用Spring Security完成了登录注销功能&#xff0c;这里继续说一下注册、密码加密和找回密码&#xff0c;代码注释较清晰。 一、web层 控制 StudentController.java package …

自动驾驶需要做哪些测试?

来源&#xff1a;广电计量&#xff0c;文&#xff1a;李梓熙、王闻彦参考资料来源&#xff1a;《有问必答 | 自动驾驶汽车之道路“测试”与“考试”》by公安部交通管理科研所微发布自动驾驶已然成为汽车行业热词。在大家殷切的期盼下&#xff0c;近几年上市的车型&#xff0c;多…

大数据的应用-UserCF和ItemCF推荐算法

一.推荐系统 1.1 推荐系统是大数据在互联网领域的典型应用&#xff0c;它可以通过分析用户的历史记录来了解用户的喜好&#xff0c;从而主动的为用户推荐其感兴趣的信息&#xff0c;满足用户的个性化推荐需求&#xff0e; 1.2 推荐系统是自动联系用户和物品的一种工具&#x…

计算机网络之Web应用

1、web与HTTP world Wide Web&#xff1a; 网页 网页互相链接 网页包含多个对象&#xff1a; 对象&#xff1a; HTML文件、JPEG图片、视频文件、动态脚本等 基本HTML文件&#xff1a; 包含对其他对象引用的链接 对象的寻址&#xff1a; URL&#xff08;Uniform Resource Locato…

HBase错误解决(启动Hbase出现错误的替换,启动hbase shell出现ERROR KeeperErrorCode=NoNode for /hbase/master)

&#xff11;&#xff0e;问题描述 我查阅资料发现&#xff0c;网上很多人和我出现相同的错误&#xff0c;却没有一个可以解决的教程&#xff0c;于是我在解决了我的一个错误后就立即写了这篇文章&#xff0c;需要能帮到一些人&#xff0c;文章不一定对每个人都有效&#xff0c…

如何使用jmeter进行并发登录测试

第一种方案直接从数据库中获取账号和密码 1、设置线程数为20 &#xff0c;我们的并发用户量就是20个用户同时登录 2、添加定时器 3、设置集合点&#xff0c;当用户数量达到20个的时候再同时请求进行登录操作 4、添加配置元件&#xff1a;JDBC Connection Configuration 5、添加…

云计算与分布式系统课程学习笔记(一)——云计算简介

大数据对于系统架构的需求 显式的需求 海量计算和存储快速计算 隐式的需求 数据的快速传输灵活性低成本 如何实现这些需求&#xff1f; 并行化&#xff08;并行化的理念存在于计算机方方面面&#xff09; 并行请求&#xff08;分配给多个计算机&#xff09;并行线程&…

DeepMind用神经网络求解MIP后,攻破运筹学只是时间问题?你想多了

来源&#xff1a;杉数科技作者&#xff1a;皇甫琦、葛冬冬、杉数科技COPT开发组Google的DeepMind团队最近官宣了一篇神经网络(Neural Networks)求解MIP论文。一石激起千层浪&#xff0c;在国内外的运筹优化社群引起了讨论。部分围观吃瓜群众纷纷表示&#xff1a;"This is …

计算机视觉-SIFT

一.SIFT(Scale Invariant Feature Transform) 算法 1.图像尺度空间 要让计算机能够对物体在不同尺度下有一个统一的认知&#xff0c;就要需要考虑图像在不同尺度(远近&#xff0c;大小&#xff0c;颜色区别等)下存在的特点&#xff0e;尺度空间的获取通常使用高斯模糊来实现&…

世界上最好的光刻机为什么来自荷兰?【物联网智商精选】

来源: 大数据实验室“是说芯语”已陪伴您439天现在微电子集成电路技术对世界的各种科技电子产品越来越应用广泛了&#xff0c;一个国家的发展越来越离不开高端芯片了&#xff0c;一个国家越是发展得越快对高端芯片需求量越大&#xff0c;比如我国的芯片需求占世界的50&#xff…

云计算与分布式系统课程学习笔记(二)——Linux基本命令的使用与熟悉

&#xff08;1&#xff09; jps 【显示当前系统的java进程情况&#xff0c;及其id号】 -q只显示pid&#xff0c;不显示class名称,jar文件名和传递给main方法的参数-m输出传递给main方法的参数-l输出主类的完整包名或者jar文件完整路径名-v输出传递给JVM的参数 编写一个JSPDemo…

【转】为了修复打码女神脸,他们提出二阶段生成对抗网络EdgeConnect

当图像缺失部分太多的时候&#xff0c;结合多阶段方法和边缘先验信息&#xff0c;这个 GAN 实现了高还原度的图像修复&#xff0c;玩法还不止于此。 在过去几年中&#xff0c;深度学习技术在图像修复方面取得了显着进步。然而&#xff0c;许多这些技术无法重建合理的结构&#…

高等数学、线性代数、概率论、几何这些知识可以用来干什么?

来源&#xff1a;图灵人工智能应该会有很多模友在开始学习数学分析和高等数学时&#xff0c;第一反应是&#xff1a;但其实大多数人所用的教材&#xff0c;从大众角度看还没有到一种极致精确的架构数学的程度。大多数的教材所做的还是“我教会你怎么弄这个东西就行了&#xff0…

CentOS7.7安装MySQL5.6并配置环境变量(详细版)

i. tar包下载 官网下载 https://dev.mysql.com/downloads/mysql/网盘获取 链接&#xff1a;https://pan.baidu.com/s/1DpULc0qQ4hqx6HWUwRilpw 提取码&#xff1a;tgdv ii. 安装所需环境 yum -y install make gcc-c cmake bison-devel ncurses-develiii. 解压tar包&#xf…

多少血的教训,才能换来对自动驾驶的严格限定、真实了解和正确使用?

来源&#xff1a;胡延平EarthRambler真的到了应该出台严格的安全措施的时候&#xff0c;而&#xff1c;道路交通安全法*修订建议稿&#xff1e;如何明确责任成为关从最新一起车祸的碰撞情况看&#xff0c;高速公路追尾卡车&#xff0c;雷达对前方目标的识别和驾驶系统的反应可能…

java并发编程-----深入剖析ThreadLocal

一.对ThreadLocal的理解 ThreadLocal&#xff0c;很多地方叫做线程本地变量&#xff0c;也有些地方叫做线程本地存储&#xff0c;其实意思差不多。可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本&#xff0c;那么每个线程可以访问自己内部的副本变量。 这句…

VMware下主机与虚拟机剪切板独立,无法直接复制粘贴

看了很多博客都说需要重新安装vmware tools&#xff0c;但我使用的是这种方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 关闭虚拟机点击编辑虚拟机设置->选项选择客户机隔离&#xff0c;勾选上启动复制粘贴即可&#xff08;如果之前就已经勾选上但失效的情…

教AI区分因果关系和相关性,将改变下一代 AI 的研发

来源&#xff1a;ScienceAI编辑&#xff1a;萝卜皮多年前&#xff0c;AI 领域曾发生过一件荒唐而有趣的事情。据说&#xff0c;研究人员开发了一种对医院数据进行训练的算法。这个算法发现&#xff0c;「患有哮喘的肺炎患者的治愈表现&#xff0c;比没有哮喘的肺炎患者更好」&a…

Java Socket实现客户端服务端之间的通信

Java Socket Java Socket编程用于在不同JRE上运行的应用程序之间的通信。Java Socket编程可以是面向连接的或无连接的。Socket和ServerSocket类用于面向连接的套接字编程&#xff0c;DatagramSocket和DatagramPacket类用于无连接套接字编程。 此Demo将进行单向客户端和服务器…