分治ヾ(◍^▽^◍)ノ゙

普通分治

思想:分成两个部分分别处理,然后合并答案



朋友

一张无向图,每次询问a到b不经过c的最短路。
n<=200,Q<=1e5

Floyd,不支持删点,可用分治加点模拟删点。
复杂度 O ( n 3 log ⁡ n ) O(n^3\log n) O(n3logn)


[ZJOI2016] 旅行者

给定一个网络图和若干组询问,每次询问两点间最短路。
n*m<=2e4,q<=1e5

沿着长边从中间切成两半,是起点和终点在边的两边,将边上的点跑一边 d i j k s t r a dijkstra dijkstra


篮球

有n种物品,第i种物品有 c i c_i ci个,初始代价为ai,被选中一次代价就会减少 b i b_i bi(第 k k k次选的代价就是 a i a_i ai- ( k (k (k- 1 ) b i 1)b_i 1)bi),对于 k k k= 1 1 1 m m m,总共选 k k k件物品出来代价的最小值是多少。
n<=1000,m<=10000

一个性质,最多只有一种物品不被全选。
d i v i d e [ l , r ] divide[l,r] divide[l,r]表示一个 d p dp dp数组,不全选的在 [ l , r ] [l,r] [l,r]中,分治。
边用 01 01 01背包维护。
复杂度 O ( n m log ⁡ n ) O(nm\log n) O(nmlogn)


奖杯

n n n个数字,找到最长区间 [ l , r ] [l,r] [l,r]使得该区间每种数字出现次数都>= f [ r − l + 1 ] f[r-l+1] f[rl+1] f f f是一个单调不增的序列。
n<=1e6

维护每种数字出现次数,然后从两端同时开始分治找到第一个不符合要求的数字。
复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)


匹配

n n n种糖果,每种糖果有两个,但你不知道这些糖果是哪一种,有两种操作:
1.往口袋里放一颗糖果
2.从口袋里拿出一颗糖果
每次操作后你可以知道口袋里有多少种不同的糖果。输出答案将糖果两两配对。
n<=43000


不讲武德(弱化版)

给定一个二元组 ( a i , b i ) (a_i,b_i) (ai,bi),对于每个 1 1 1<= k k k<= n n n求出恰好选出 k k k个二元组使得 ( ∑ a i ) ∗ ( ( ∑ b i ) (\sum a_i)*((\sum b_i) (ai)((bi)最小。
n<=200

分治求凸包,找离当前左端点和右端点练出线段中间最远的点,找不到即无解。



CDQ分治

先算左侧再算左侧对右侧的贡献的分治


三维偏序

有一个三元组 ( a i , b i , c i ) (a_i,b_i,c_i) (ai,bi,ci),对于每个三元组,你要求出有多少个其他三元组 ( a j , b j , c j ) (a_j,b_j,c_j) (aj,bj,cj)满足 a j a_j aj<= a i a_i ai&& b j b_j bj<= b i b_i bi&& c j c_j cj<= c i c_i ci
n<=1e5

先按 a i a_i ai排序,分治计算自己左侧的答案,在计算对右侧的贡献。因为是按 a i a_i ai排序,所以就退化成了一个二维的偏序。按 b i b_i bi排序后树状数组维护即可。


最长偏序链

n n n个三元组 ( a i , b i , c i ) (a_i,b_i,c_i) (ai,bi,ci),求最多的三元组满足均存在偏序关系。

与上一题思想类似,只是把计数改为dp维护即可。


长者

一个长度为n的排序,有些位置已经确定,需要确定剩下位置上的数字使得最大化排列的最长上升子序列长度。

因为限制是一个排列,所以数字各不相同。
有一个不优的dp想法:
状态: f [ i ] [ j ] f[i][j] f[i][j]表示长度为 i i i的前缀以 j j j为结尾的 L I S LIS LIS长度。
转移伪代码如下:

if(/*当前位置已确定*/)
	f[i][p[i]]=max(f[i-1][j]|j<p[i])+1;
else
	f[i][j]=max(f[i-1][k]+1|k<j,f[i-1][j]);

然后可以考虑一下一维dp
状态: f [ i ] f[i] f[i]表示以 i i i位置结尾的最长 L I S LIS LIS i i i位置已确定。
转移:枚举已确定的位置, f [ i ] = m a x ( f [ j ] + m i n ( c n t [ i ] − c n t [ j ] , r e m [ p [ i ] ] − r e m [ p [ i ] ] ) ∣ p [ j ] < p [ i ] ) + 1 f[i]=max(f[j]+min(cnt[i]-cnt[j],rem[p[i]]-rem[p[i]])|p[j]<p[i])+1 f[i]=max(f[j]+min(cnt[i]cnt[j],rem[p[i]]rem[p[i]])p[j]<p[i])+1
c n t cnt cnt表示前缀中没有确定的数字个数
r e m rem rem表示< p [ i ] p[i] p[i]且未确定的数字个数
因为满足 p [ j ] p[j] p[j]< p [ i ] p[i] p[i] j j j< i i i,所以min可分情况讨论。

  1. c n t [ i ] cnt[i] cnt[i]- c n t [ j ] cnt[j] cnt[j]>= r e m [ p [ i ] ] rem[p[i]] rem[p[i]]- r e m [ p [ i ] ] rem[p[i]] rem[p[i]] => c n t [ i ] cnt[i] cnt[i]- r e m [ p [ i ] ] rem[p[i]] rem[p[i]]>= c n t [ j ] cnt[j] cnt[j]- r e m [ p [ j ] ] rem[p[j]] rem[p[j]]
  2. c n t [ i ] cnt[i] cnt[i]- c n t [ j ] cnt[j] cnt[j] < r e m [ p [ i ] ] rem[p[i]] rem[p[i]]- r e m [ p [ i ] ] rem[p[i]] rem[p[i]] => c n t [ i ] cnt[i] cnt[i]- r e m [ p [ i ] ] rem[p[i]] rem[p[i]] < c n t [ j ] cnt[j] cnt[j]- r e m [ p [ j ] ] rem[p[j]] rem[p[j]]

所以可以分治下标,按 c n t [ i ] cnt[i] cnt[i]- c n t [ j ] cnt[j] cnt[j]排序。


HDU 6800

一个二维点序列 ( a i , b i ) (a_i,b_i) (ai,bi),把它拆成两个子序使得两个子序列中相邻两项的曼哈顿距离和最小。

状态: f [ i ] [ j ] f[i][j] f[i][j]表示当前 d p dp dp了前 i i i个,另一个子序列结尾为 j j j的最小代价。
转移伪代码如下:

if(j<i-1) 
	f[i][j]->f[i-1][j]
else //枚举k
	f[i][j]=f[i-1][k]

所以我们可以设 g [ i ] g[i] g[i]= f [ i , i f[i,i f[i,i- 1 ] 1] 1]
g [ i ] g[i] g[i]= m i n ( g [ j ] min(g[j] min(g[j]+ d [ j − 1 ] [ i ] d[j-1][i] d[j1][i]- s [ j ] ) s[j]) s[j])+ s [ i − 1 ] s[i-1] s[i1]
然后分治就可做了。



线段树分治


序列

n n n个物品,第 i i i种物品第一次选择的收益是 a i a_i ai,之后每一次选择的收益都是 b i b_i bi,代价始终为 c i c_i ci,在总代价不超过 m m m的情况下最大化总收益。
Q Q Q次询问,每次修改一个物品的两类收益,对于每次修改输出答案(之前的修改对后面有影响)。
n,m,Q<=2000

先考虑没有修改的情况:
强制选一个 a i a_i ai,转移到 f [ i ] [ j f[i][j f[i][j+ c i ] c_i] ci] f [ i ] [ j ] f[i][j] f[i][j]= m a x ( f [ i ] [ j ] , f [ i ] [ j max(f[i][j],f[i][j max(f[i][j],f[i][j- c [ i ] c[i] c[i]+ b [ i ] ) b[i]) b[i]),与 f [ i f[i f[i- 1 ] [ j ] 1][j] 1][j] m a x max max
若存在修改,它的贡献为一段连续的 d f s dfs dfs
所以每个物品可能会被修改多次,所以可以把每个区间放入线段树中,线段树分治维护。


无题

n n n个物品,每个物品有大小和权值,查询一个区间中的物品拿出来做大小为 w w w的背包的结果
n,m<=1e4,w<=100

线段树分治。
考虑n,m<=1e5,可用双栈 维护


luogu P5163
老师高一出的黑题 我是垃圾

维护一个动态有向图,支持三种操作:
1.删掉一条有向边
2.改变一个点的权值
3.询问一个点所在的强连通分量里前 k k k大的权值之和
n,m<=2e5 允许离线

首先删边可以反过来加边。
可以整体二分 来计算出每条边被缩。
二分一个时间mid,把出现时间<=mid的边跑一边tarjan,如果当前边被缩过了,就递归到左边,否则递归右边,递归到底时用并查集 缩边。就把时间全部求出,然后按时间排序就变成了无向图。
所以我们可以用线段树合并,查询线段树二分即可。



二进制分组

有1000桶水,其中有一桶有毒,你可以要来若干只小白鼠让它们喝桶里的水,一只小白鼠可以喝多个桶里的水,毒性会在一天后发作。
你需要在一天内找出有毒的那桶水,至少需要多少只小白鼠?


CF1365G
传送门我真不想敲题面了
首先显然有20次的二进制分组做法, 但是题目要求13次,还是多了,所以要想办法优化
以发现 C 13 6 C_{13}^6 C136>1000,这就代表着我们对这1000个数用一个13位的有6个1的二进制标记, 每一个的二进制都是不同的, 而且绝对没有包含关系, 这样的话, 我们就可以去求出每一个位置上的权值

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值