[学习笔记]线段树分治

https://www.luogu.org/blog/Miracevin/shuo-ju-jie-gou

一种离线处理方法

可以处理“具体哪个修改对询问有影响”、可以贡献不独立、可以支持插入删除

关键是把一个修改看成一个区间,每个询问是一个叶子,修改在线段树上打标记

例题6:

例题 7
• 给出一张图
• 对每个点求出强制这个点点度为 1 的最小生成树的权值

• ? ≤ 100000, ? ≤ 300000

等价于:每个边存在三段:[1,x-1],[x+1,y-1][y+1,n]

LCT维护最小生成树

i的答案再加上和i相邻的边权最小值

 

例题 8
• 给一棵树,边有边权
• 每次操作是删除一条边并加入一条边,保证操作完还是树
• 你需要维护有多少点对 ?, ? 的路径上所有数的最大公约数是 1
• ? ≤ 100000, ?? ≤ 100000, ? ≤ 30000

gcd这个东西太难搞。

反演一下得到:

ans=∑miu(d)f(d)

f(d)表示路径上的点都是d的倍数的点对的个数

也就是,所有是d的倍数的点构成的若干个联通块,f(d)=∑szi*(szi-1)/2

 

考虑对每个边出现的区间进行线段树分治

然后dfs,用按秩合并并查集维护每个d的f(d),也就是维护好联通块∑szi*(szi-1)/2

每加入一个边,枚举这个边两边的点的gcd的约数d,再对每个并查集进行维护。

栈序撤销

总共每个边只会出现sqrt(w)次,w是边权,也即gcd(x,y)

(当然LCT也可以,常数爆炸就是了)

 

例题 9
• (CTSC2016时空旅行)
• 你需要维护若干个版本的集合,每个集合元素是 ?, ?
• 每次可以扩展一个版本,扩展内容为加一个新元素或删除一个已
有元素
• 每次询问一个 ?,要你在给定版本 ? 的集合中找出 ?, ? 使得
? − ? 2 + ? 最小
• ?, ? ≤ 1000000

[CTSC2016]时空旅行

也比较神仙

先推性质咯

 

发现版本扩展这个东西是一个树形结构

每个元素存在的区间,直接按照版本分的话,可以分层O(m),直接挂掉

于是考虑用dfn序!,x一定出现在x的子树里,并且删掉x这个元素操作,可以把这个区间再分成若干小区间(扣除小子树)

但是总区间数是m

为线段树分治打下基础

 

最优化的式子明显是斜率优化,维护下凸壳,横坐标是x,纵坐标是x*x+v,斜率是2y

考虑怎么处理询问:

1.dfs?不支持单点增量,只能平衡树暴力维护凸包。。。。复杂度不敢想象。

2.考虑每个修改区间对叶子询问的影响。(毕竟可以直接取min)

既然已经离线,我们可以排序!把修改按照x排序,询问按照斜率k排序,按照顺序加入线段树,

这样,每个线段树的点维护一个vector(其实是单调队列),就是这个区间的凸包,x递增,所以单点增量即可

再维护一个vector,每个询问插入的时候,k从小到大,再加入这个vector里面。然后单调队列即可。

3.考虑对每个询问,找父链上的凸包来更新答案

只用凸包的一个vector即可。

询问k从小到大,每次找整个链上的凸包做一下。每个区间可以单调队列处理。

(这题横坐标有相同的,要注意)

 

 


upda:2019.5.17

线段树分治套虚树?

询问区间放上去,关键点放上去,建立虚树再DP

O(nlog^2)

【2018 12月集训 Day2】小奇的危机

 

转载于:https://www.cnblogs.com/Miracevin/p/10355084.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值