[非旋平衡树]fhq_treap概念及模板,例题:普通平衡树,文艺线段树

文章目录

  • 概念
  • 全套模板
    • push_up模板
    • split拆树模板(按权值拆)
    • split拆树模板(按个数拆)
    • merge合并模板(地址版)
    • merge合并模板(带返回根)
    • 区间模板
    • insert插入模板
    • delete删除模板
    • find_kth找第k大模板
    • get_rank找排名模板
    • pre找前驱模板
    • suf找后驱模板
  • 例题1:普通平衡树
    • 题目
    • 代码实现
  • 例题2:文艺线段树
    • 题目
    • 代码实现

建议在看这篇博客之间要了解一下带旋Treap
我会在模板前面写上一部分的思路讲解,帮助各位理解

概念

根据它的名字我们也可以得知,这种数据结构就是treaptreaptreap的后代,只不过不带旋转,其余都是一致的
所以在运用和代码上会有所异同。它比treaptreaptreap多了splitsplitsplit(拆树)和mergemergemerge(合并)操作,所以得到的结果是可以多处理数据结构的区间问题。以一换一
在这里插入图片描述接下来我们就重点介绍splitsplitsplitmergemergemerge还有区间操作到底是个什么玩意儿???

全套模板

因为是自己修改后的模板,可能会有不严谨处,欢迎大家指出并更正!
在这里插入图片描述
先照样介绍各个数组变量的含义:
SizeSizeSize:表示节点数量也可作最后一个点编号
cnt[p]cnt[p]cnt[p]:表示编号为ppp,值为xxxtreaptreaptreap中插入的次数
key[p]key[p]key[p]:表示该点ppp的值为xxx
rd[p]rd[p]rd[p]:就是我们自己搞的修正值,用rand()rand()rand()函数随机生成
siz[p]siz[p]siz[p]:编号为ppp的子树包括本身在内的节点数量即大小
son[p][2]son[p][2]son[p][2]son[p][0]son[p][0]son[p][0]表示p的左儿子,son[p][1]son[p][1]son[p][1]表示ppp的右儿子


push_up模板

先蓄蓄力,放松放松

void push_up ( int x ) {siz[x] = siz[son[x][0]] + siz[son[x][1]] + cnt[x];
}

split拆树模板(按权值拆)

splitsplitsplit拆树的结果就是把树根据要求值kkk拆成两半

左边全是值≤k≤kk的点,右边全是值>k>k>k的点

上图讲解:充分运用画过的图,我带领大家走一遍,再不懂就不管本蒟蒻了
在这里插入图片描述
假设我们的kkk为35,那么首先从根节点1开始,发现1的权值25小于35

这个时候我们就能确定根节点以及根节点的左子树的权值全都是小于35的

那么这个时候它们是属于拆分后左边的子树

但是我们会发现根节点的右子树也存在可能值大于35的节点

我们就需要继续往下拆分

接下来走到节点3,发现权值大于35,可以得出的结论是3节点以及它的右子树的权值都是大于35的,应该是属于拆分后的右子树

但是同样的我们不能肯定它的左儿子是否也是归属于右边,继续往左拆分

最后走到了叶子节点,发现节点4的权值小于等于35也应该归于左边

这个时候就把节点4接到根节点1的右边,成功把1和3的边给断掉

最后一层一层回溯,最顶层的两个根节点就分别为1,3

节点1统领了所有权值小于等于kkk的子树,节点3统领了所有权值大于kkk的子树

我的写法是传地址,这样就直接更改了


void split ( int p, int &l, int &r, int x ) {if ( ! p ) {l = r = 0;return;}if ( key[p] <= x ) {l = p;split ( son[p][1], son[p][1], r, x );push_up ( l );}else {r = p;split ( son[p][0], l, son[p][0], x );push_up ( r );}
}

split拆树模板(按个数拆)

此代码有适用范围!!!在某些题中会出错

按下标拆的思路与按权值拆是一样的,只不过往右子树找的时候记得把左子树和根占得位置给减掉即可

拆出来的左子树的个数恰好是给定的kkk,右子树就是剩下来的所有点

void split_id ( int p, int &l, int &r, int x ) {if ( ! p ) {l = r = 0;return;}if ( siz[son[p][0]] + 1 <= x ) {l = p;split_id ( son[p][1], son[p][1], r, x - siz[son[p][0]] - 1 );push_up ( l );}else {r = p;split_id ( son[p][0], l, son[p][0], x );push_up ( r );}
}

merge合并模板(地址版)

我们可以发现拆分子树的时候,改变了树的形态,这也是无法进行treaptreaptreap的旋转操作的一个原因,
百因必有果,你的报应就是我 在这里插入图片描述

既然方便了splitsplitsplit拆分,改变了树的形态,我们就必须再写一个补丁函数,把树进行还原修复

但是我们不再是使用权值kkk进行,我们思考treaptreaptreap用旋转的目的是为了维护树的键值不是从大到小就是从小到大

反正就是要有一定的顺序

那么mergemergemerge的目的也是维护树的键值有顺序

本来splitsplitsplit拆的树也是我们维护好了顺序的

所以mergemergemerge合并的时候根据键值顺序来合并,也能还原splitsplitsplit所拆的树
在这里插入图片描述
在这里我仍然选择的传地址直接改在原来的地方,如果把上边的splitsplitsplit理解了,那么我相信这个也就很好理解了

void merge ( int &p, int x, int y ) {if ( ! x || ! y ) {p = x + y;return;}if ( rd[x] < rd[y] ) {p = x;merge ( son[p][1], son[p][1], y );}else {p = y;merge ( son[p][0], x, son[p][0] );}push_up ( p );
}

merge合并模板(带返回根)

int merge ( int x, int y ) {if ( ! x || ! y )return x + y;if ( rd[x] < rd[y] ) {son[x][1] = merge ( son[x][1], y );push_up ( x );return x;}else {son[y][0] = merge ( x, son[y][0] );push_up ( y );return y;}
}

区间模板

其实就是先把这个区间[l,r][l,r][l,r]拆出来然后搞一波,再把它合并回去

可以理解为先把部队里某一个方阵的士兵扯出来再捅几刀最后再让他们归队,好残忍

void XXX ( int x, int y ) {int l, r, L, R;spilt ( root, l, r, y );split ( l, L, R, x - 1 );//区间里面进行的操作merge ( l, L, R );merge ( root, l, r ); 
}

我们以翻转reversereversereverse为例,小声bb:是为了让你们做文艺平衡树更简单

void reverse ( int x, int y ) {int l, r, L, R;spilt ( root, l, r, y );split ( l, L, R, x - 1 );lazy[R] = !lazy[R];//对[x,y]区间进行打标,1表示翻转,0表示没有翻转 merge ( l, L, R );merge ( root, l, r ); 
}

简单过渡一下:其实多做几道题多用用模板会对代码更加理解,为了方便各位理解下面更改的函数,在这里简单总结一下splitsplitsplitmergemergemerge的思路

split(root,l,r,x)split(root,l,r,x)split(root,l,r,x)表示把以rootrootroot为根的子树按照权值xxx拆分,lll存储着小于等于xxx的子树的根,rrr存储着大于xxx的子树的根

merge(root,l,r)merge(root,l,r)merge(root,l,r)表示把一棵子树的根为lll和另一棵子树的根为rrr合并为一棵根为rootrootroot的新根

那么其余的操作都可以用splitsplitsplitmergemergemerge改变我们以前的写法,新朋友就要多用用嘛!


insert插入模板

insertinsertinsert之前我们是用的递归方式,在这里就要充分运用splitsplitsplitmergemergemerge

我声明一下,很多很多篇博客都是直接新建一个节点,本蒟蒻就不理解了,对于一个点它可能已经出现在树上了,这个时候就直接cnt++cnt++cnt++,为什么要选择新建点呢?

所以我就费了九牛二虎之力写出了自己想要的模板

当然对于某部分的题各个点之间是互不相同的,或其它特殊的要求,我的代码就与大佬们成为一流的了,这个时候就可以删掉我代码中if的判断即可,不删也不影响,最多代码长了一丢丢而已啦~

  • 首先我们把树先拆成权值都≤x≤xx的子树和权值都>x>x>x的子树
  • 再把权值≤x≤xx的子树拆分成权值≤x−1≤x-1x1的树和权值>x−1>x-1>x1也就是权值等于xxx的树
  • 接着我们就判断储存权值等于xxx的树的节点是否为空,
    • 如果为空就意味着树上并没有该点,就新建一个点;
    • 否则就直接cnt++cnt++cnt++updateupdateupdate一下
  • 拆了就要合并,我们怎么拆的就怎么倒着并回去,很简单的,本蒟蒻都能自己打出来
void insert ( int x ) {int l, r, L, R;split ( root, l, r, x );split ( l, L, R, x - 1 );if ( R ) {cnt[R] ++;push_up ( R );merge ( l, L, R );merge ( root, l, r );}else {++ Size;cnt[Size] = siz[Size] = 1;rd[Size] = rand ();key[Size] = x;merge ( l, L, Size );merge ( root, l, r );}
}

delete删除模板

仿照insertinsertinsert的思路

  • 先把值为xxx的这个点拆出来
  • 接下来判断如果这个点插入的次数是否大于1
    • 如果大于可以直接cnt−−cnt--cnt,该点不会消失,倒着合并回去;
    • 否则该点就应该消失在树上,我们可以通过不让它参与合并,排挤它 ,那么它就不会出现在树上了,直接把值小于等于x−1x-1x1的树和值大于xxx的树合并即可
      在这里插入图片描述
void delet ( int x ) {int l, r, L, R;split ( root, l, r, x );split ( l, L, R, x - 1 );if ( R && cnt[R] > 1 ) {cnt[R] --;push_up ( R );merge ( l, L, R );merge ( root, l, r );}elsemerge ( root, L, r );
}

剩下的查找其实是可以照搬的,但是我还是给大家分享一些其它的写法吧!!


find_kth找第k大模板

这个我还是很喜欢这种写法的,所以就不更改了
在这里插入图片描述

int find_kth ( int rt, int x ) {if ( siz[son[rt][0]] >= x )return find_kth ( son[rt][0], x );else if ( siz[son[rt][0]] + cnt[rt] < x )return find_kth ( son[rt][1], x - siz[son[rt][0]] - cnt[rt] );elsereturn key[rt];
}
//非递归结构体版本 ↓
void find_val( int x ) {int now = rt;while( 1 ) {if( x <= t[t[now].lson].siz ) now = t[now].lson;else if( x <= t[t[now].lson].siz + t[now].cnt ) break;else x -= ( t[t[now].lson].siz + t[now].cnt ), now = t[now].rson;}printf( "%d\n", t[now].val );
}

Upd:
下面求排名为 xxx 的数的方法不一定是对的。
因为按照个数大小分裂代码的正确性当且仅当数据中每个数互不相等。
显然,设想某个数有若干个,占据了排名为一段的区间,如果按照 x/x−1x/x-1x/x1 的个数分,全都划在该数身上,则 RRR 就是个空子树了。
如果直接判 RRR 是否为空也是错误的。
但是我也不知道为什么??!!所以还是麻烦大家写上面的方法。
也有可能是因为博主的其它模板某些限制把。。。
数据结构真是一个比一个玄学!!凸(艹皿艹 )

void find_val( int x ) {int l, r, L, R;split_siz( rt, x, l, r );split_siz( l, x - 1, L, R );printf( "%d\n", t[R].val );rt = merge( merge( L, R ), r );
}

get_rank找排名模板

我们就充分运用新学函数,思考一下如果把≤x−1≤x-1x1的树拆出来
那么它的大小+1+1+1是不是就是xxxrankrankrank排名呢!!!实在是
在这里插入图片描述

void get_rank ( int x ) {int l, r;split ( root, l, r, x - 1 );printf ( "%d\n", siz[l] + 1 );merge ( root, l, r );
}

pre找前驱模板

找前驱,这里是严格小于的情况,先拆分一下看有木有权值小于xxx的点
有的话我们就调用findfindfind_kthkthkth在拆分出来的那棵子树中去找最后一个也就是xxx的前一个

int pre ( int x ) {int l, r, result;split ( root, l, r, x - 1 );if ( siz[l] )result = find_kth ( l, siz[l] );elseresult = INF;merge ( root, l, r );return result;
}

suf找后驱模板

找后驱,与找前驱相似,这里是严格大于的情况,先拆分一下看有木有权值大于xxx的点
有的话我们就调用findfindfind_kthkthkth在拆分出来的那棵子树中去找第一个也就是xxx的后一个

int suf ( int x ) {int l, r, result;split ( root, l, r, x );if ( siz[r] )result = find_kth ( r, 1 );elseresult = INF;merge ( root, l, r );return result;
}

Upd:当然你可以直接暴力的裂开。以找前驱为例,把 ≤x−1\le x-1x1 的子树列出来,从子树的根开始疯狂走右儿子(如果有)。

void find_pre( int x ) {int l, r;split_val( rt, x - 1, l, r );int now = l;while( t[now].rson ) now = t[now].rson;printf( "%d\n", t[now].val );rt = merge( l, r );
}void find_suf( int x ) {int l, r;split_val( rt, x, l, r );int now = r;while( t[now].lson ) now = t[now].lson;printf( "%d\n", t[now].val );rt = merge( l, r );
}

在这里插入图片描述老套路来些题目练习练习,实在是太模板了,直接器官移植都能过,哎╮(╯▽╰)╭

例题1:普通平衡树

题目

点击查看

代码实现

一样一样的,进行器官移植即可

#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 100005
#define INF 0x7f7f7f7f
int root, n, Size;
int son[MAXN][2], cnt[MAXN], siz[MAXN], rd[MAXN], key[MAXN];void push_up ( int x ) {siz[x] = siz[son[x][0]] + siz[son[x][1]] + cnt[x];
}void split ( int p, int &l, int &r, int x ) {if ( ! p ) {l = r = 0;return;}if ( key[p] <= x ) {l = p;split ( son[p][1], son[p][1], r, x );push_up ( l );}else {r = p;split ( son[p][0], l, son[p][0], x );push_up ( r );}
}void merge ( int &p, int x, int y ) {if ( ! x || ! y ) {p = x + y;return;}if ( rd[x] < rd[y] ) {p = x;merge ( son[p][1], son[p][1], y );}else {p = y;merge ( son[p][0], x, son[p][0] );}push_up ( p );
}void insert ( int x ) {int l, r, L, R;split ( root, l, r, x );split ( l, L, R, x - 1 );if ( R ) {cnt[R] ++;push_up ( R );merge ( l, L, R );merge ( root, l, r );}else {++ Size;cnt[Size] = siz[Size] = 1;rd[Size] = rand ();key[Size] = x;merge ( l, L, Size );merge ( root, l, r );}
}void delet ( int x ) {int l, r, L, R;split ( root, l, r, x );split ( l, L, R, x - 1 );if ( R && cnt[R] > 1 ) {cnt[R] --;push_up ( R );merge ( l, L, R );merge ( root, l, r );}elsemerge ( root, L, r );
}int find_kth ( int rt, int x ) {if ( siz[son[rt][0]] >= x )return find_kth ( son[rt][0], x );else if ( siz[son[rt][0]] + cnt[rt] < x )return find_kth ( son[rt][1], x - siz[son[rt][0]] - cnt[rt] );elsereturn key[rt];
}int pre ( int x ) {int l, r, result;split ( root, l, r, x - 1 );if ( siz[l] )result = find_kth ( l, siz[l] );elseresult = INF;merge ( root, l, r );return result;
}int suf ( int x ) {int l, r, result;split ( root, l, r, x );if ( siz[r] )result = find_kth ( r, 1 );elseresult = INF;merge ( root, l, r );return result;
}void get_rank ( int x ) {int l, r;split ( root, l, r, x - 1 );printf ( "%d\n", siz[l] + 1 );merge ( root, l, r );
}int main() {scanf ( "%d", &n );while ( n -- ) {int opt, x;scanf ( "%d %d", &opt, &x );switch ( opt ) {case 1 : insert ( x ); break;case 2 : delet ( x ); break;case 3 : get_rank ( x ); break;case 4 : printf ( "%d\n", find_kth ( root, x ) ); break;case 5 : printf ( "%d\n", pre ( x ) ); break;case 6 : printf ( "%d\n", suf ( x ) ); break;}}return 0;
}

例题2:文艺线段树

题目

点击查看题目

代码实现

在这里因为涉及到一个区间翻转问题,我们就可以类比线段树打lazylazylazy标记,也对treaptreaptreap树打一个标记
那么在我们进行split,mergesplit,mergesplit,merge操作时,要保证对于一个点,它的左儿子和右儿子是对的,所以这里要写一个标记下放的pushdownpushdownpushdown
最后输出数列的时候也采用递归的方式,左中右的中序遍历,在这之间顺便进行标记下放

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 100005
#define INF 0x7f7f7f7f
int root, n, Size, m;
int son[MAXN][2], cnt[MAXN], siz[MAXN], rd[MAXN], key[MAXN];
bool lazy[MAXN];void push_up ( int x ) {siz[x] = siz[son[x][0]] + siz[son[x][1]] + cnt[x];
}void pushdown ( int x ) {if ( x && lazy[x] ) {swap ( son[x][0], son[x][1] );lazy[son[x][0]] = !lazy[son[x][0]];lazy[son[x][1]] = !lazy[son[x][1]];lazy[x] = 0;return; }
}void split ( int p, int &l, int &r, int x ) {if ( ! p ) {l = r = 0;return;}pushdown ( p );//千万不要放在if-else里面,先把标记下放去交换左右儿子//确保此时p的左右儿子是真的,不然就报错了/(ㄒoㄒ)/~~if ( siz[son[p][0]] + 1 <= x ) {l = p;split ( son[p][1], son[p][1], r, x - siz[son[p][0]] - 1 );push_up ( l );}else {r = p;split ( son[p][0], l, son[p][0], x );push_up ( r );}
}void merge ( int &p, int x, int y ) {if ( ! x || ! y ) {p = x + y;return;}if ( rd[x] < rd[y] ) {pushdown ( x );p = x;merge ( son[p][1], son[p][1], y );}else {pushdown ( y );p = y;merge ( son[p][0], x, son[p][0] );}push_up ( p );
}void insert ( int x ) {int l, r, L, R;split ( root, l, r, x );split ( l, L, R, x - 1 );if ( R ) {cnt[R] ++;push_up ( R );merge ( l, L, R );merge ( root, l, r );}else {++ Size;cnt[Size] = siz[Size] = 1;rd[Size] = rand ();key[Size] = x;merge ( l, L, Size );merge ( root, l, r );}
}void delet ( int x ) {int l, r, L, R;split ( root, l, r, x );split ( l, L, R, x - 1 );if ( R && cnt[R] > 1 ) {cnt[R] --;push_up ( R );merge ( l, L, R );merge ( root, l, r );}elsemerge ( root, L, r );
}void print ( int x ) {if ( ! x )return;pushdown ( x );print ( son[x][0] );printf ( "%d ", key[x] );print ( son[x][1] );
}void reverse ( int x, int y ) {int l, r, L, R;split ( root, l, r, y );split ( l, L, R, x - 1 );lazy[R] = !lazy[R];merge ( l, L, R );merge ( root, l, r );
}int main() {scanf ( "%d %d", &n, &m );for ( int i = 1;i <= n;i ++ )insert ( i );for ( int i = 1;i <= m;i ++ ) {int idl, idr;scanf ( "%d %d", &idl, &idr );reverse ( idl, idr );}print ( root );return 0;
}

因此这道题启示我们,随着我们的操作要求的不一样,在splitsplitsplitmergemergemerge中一些语句可能会发生顺序变换,不能盲目地去背模板,一定要理解

可能会有部分代码细节错误,因为这些题实在是水,导致有些写错的代码还是能跑过数据


在这里插入图片描述

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

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

相关文章

surging 微服务引擎 1.0 正式发布

surging 是一个分布式微服务引擎,提供高性能RPC远程服务调用&#xff0c;服务引擎支持http、TCP、WS、Mqtt协议,采用Zookeeper、Consul作为surging服务的注册中心&#xff0c;集成了哈希一致性&#xff0c;随机&#xff0c;轮询、压力最小优先作为负载均衡的算法&#xff0c;底…

YBTOJ:彩色圆环

文章目录前言题目描述InputOutputSample InputSample Output解析代码前言 尽信书&#xff0c;则不如无书 题目描述 Input 仅有一行&#xff0c;该行给出依次两个正整数N, M&#xff0c;分别表示宝石的个数和宝石在变化时可能变成的颜色种类数。 Output 应仅有一行&#xff0…

【2019CSP-J 普及组题解】数字游戏(number),公交换乘(transfer),纪念品(souvenir),加工领奖(work) CSP普及游记

文章目录T1&#xff1a;数字游戏题目CODET2&#xff1a;公交换乘题目CODET3&#xff1a;纪念品题目题解CODET4&#xff1a;加工领奖题目题解CODE关于普及组的想法&游记T1&#xff1a;数字游戏 题目 小 K 同学向小 P 同学发送了一个长度为 8 的 01 字符串来玩数字游戏&…

搭建基于Docker社区版的Kubernetes本地集群

Kubernetes的本地集群搭建是一件颇费苦心的活&#xff0c;网上有各种参考资源&#xff0c;由于版本和容器的不断发展&#xff0c;搭建的方式也是各不相同&#xff0c;这里基于Docker CE的18.09.0版本&#xff0c;在Mac OS、Win10下分别搭建了一次。一、Mac OS下搭建安装Docker …

Infinite Tree

Infinite Tree 题意&#xff1a; 题解&#xff1a; 参考博客 看了好一阵子才明白。。。emm。 我们先按照题意画出一部分树 我们先不考虑复杂度&#xff0c;这题应该怎么做&#xff1f; 题目给了每个点的权值w[i]&#xff0c;问一个点到所有的节点路径长度*点权之和最小是多少…

IdentityServer4-从数据库获取User登录并对Claims授权验证(五)

本节将在第四节基础上介绍如何实现IdentityServer4从数据库获取User进行验证&#xff0c;并对Claim进行权限设置。一、新建Web API资源服务&#xff0c;命名为ResourceAPI&#xff08;1&#xff09;新建API项目&#xff0c;用来进行user的身份验证服务。&#xff08;2&#xff…

周末狂欢赛1(玩游戏/Game,函数,JOIOI王国)

狂欢1T1&#xff1a;玩游戏 / Game题目题解代码实现T2&#xff1a;函数题目题解代码实现T3&#xff1a;JOIOI王国题目题解代码实现T1&#xff1a;玩游戏 / Game 题目 ljcc 和他的学妹在玩游戏&#xff0c;这个游戏共有 n 轮&#xff0c;在第 i 轮获胜会获得 i 分&#xff0c;…

用ABP只要加人即可马上加快项目进展(二) - 分工篇 - BDD实战篇 - .NET Core里跑Specflow...

这是<如何用ABP框架快速完成项目 >系列中的一篇文章。BDD很赞&#xff01;比TDD先进很多&#xff0c;能够大大提高编码效率。上一篇文章说了如何在.NET Core里安装Specflow. 然而文章成果只到了hello world级别。要想真的和实际业务结合&#xff0c;比如要能够IOC new cl…

【做题记录】CodeForces 做题记录

链接放的是洛谷上的链接&#xff0c;难度就是 CF 上的评分。 <details><summary>$\texttt{solution}$</summary></details> CF10D LCIS 难度&#xff1a;\(\tt{2800}\) 求两个串的最长公共上升子序列。\(n\le 500\) $\texttt{solution}$ 严重虚高题&am…

周末狂欢赛2(冒泡排序,概率充电器,不勤劳的图书管理员)

狂欢2T1&#xff1a;冒泡排序题目题解CODET2&#xff1a;概率充电器题目题解CODET3&#xff1a;不勤劳的图书管理员题目题解CODE我不这么认为。。。。 T1&#xff1a;冒泡排序 题目 下面是一段实现冒泡排序算法的 C代码&#xff1a; for(int i1; i<n; i)for(int j1; j&l…

P5659-[CSP-S2019]树上的数【贪心】

正题 题目链接:https://www.luogu.com.cn/problem/P5659 题目大意 给出nnn个点的一棵树&#xff0c;每个节点上有一个数字&#xff0c;你每次可以选择一条边删除然后交换连接的两个点的数字&#xff0c;在删完所有数字后设pip_ipi​表示数字iii所在节点编号&#xff0c;要求使…

YBTOJ洛谷P3195:玩具装箱(斜率优化dp)

传送门 文章目录前言解析代码前言 斜率优化dp&#xff0c;就是利用斜率优化的dp &#xff08;逃&#xff09; 解析 第一道斜优的题 分析题目 设sumisum_isumi​为1-i的c的前缀和 容易写出dp转移式&#xff1a; dpimin(dpj(sumi−sumji−j−1−L)2)dp_imin(dp_j(sum_i-sum_ji-…

01.微服务系列介绍

微服务系列实践 .NET CORE在开始之前呢&#xff0c;还是得废话一下&#xff0c;毕竟还是需要介绍一下这个系列我们要实现什么样的一套服务架构&#xff0c;也让大家能初步的有一个了解&#xff0c;后续实践起来也有一个完整的概念&#xff0c;相对也会容易的多。互联网架构演变…

Walker

Walker 题意&#xff1a; 一个区间[0,n]&#xff0c;区间上有两个点&#xff0c;坐标分别是pos1&#xff0c;pos2&#xff0c;速度分别是v1&#xff0c;v2&#xff0c;这两个点是在移动&#xff0c;可以随时改变移动方向&#xff0c;问当区间的每一块均被一个点或两个点移动覆…

【网络流】最大流问题(EK算法带模板,Dinic算法带模板及弧优化,ISAP算法带模板及弧优化)上下界网络流

本blog重点是代码网络流的相关概念流网络(flow network)流(flow)网络的流残留网络(residual network)增广路径(augmenting path)Edmonds-Karp算法思想bfs模板调用EK&更新残留网络流模板luogu的AC代码(EK版)Dinic算法思路时间复杂度证明bfs模板模板1模板2dfs模板不带弧优化模…

Rainbond 5.0正式发布, 支持对接管理已有Kubernetes集群

今天很高兴的向大家宣布Rainbond v5.0正式发布&#xff0c;Rainbond是开源的企业应用云操作系统&#xff0c;支撑企业应用的开发、架构、交付和运维的全流程&#xff0c;通过无侵入架构&#xff0c;无缝衔接各类企业应用&#xff0c;底层资源可以对接和管理IaaS、虚拟机和物理服…

Fibonacci

Fibonacci 题意&#xff1a; f[i]表示第i位的斐波那契数列 给定n&#xff0c;求 题解&#xff1a; 这种题一开始没什么思路&#xff0c;那么枚举就行 g(x,y) 1 是当x * y为偶数时 x * y为偶数说明&#xff1a; x是偶数&#xff0c;y也是偶数 x是奇数&#xff0c;y是偶数 而…

基于.NET Standard的分布式自增ID算法--美团点评LeafSegment

概述前一篇文章讲述了最流行的分布式ID生成算法snowflake&#xff0c;本篇文章根据美团点评分布式ID生成系统文章&#xff0c;介绍另一种相对更容易理解和编写的分布式ID生成方式。实现原理Leaf这个名字是来自德国哲学家、数学家莱布尼茨的一句话&#xff1a;There are no two …

[费用流专题]Going Home,Minimum Cost,工作安排

文章目录T1&#xff1a;Going Home题目题解CODET2&#xff1a;Minimum Cost题目题解CODET3&#xff1a;工作安排题解CODET1&#xff1a;Going Home 题目 On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, e…

Sky Garden

Sky Garden 题意&#xff1a; 画n个圆和m条直线&#xff0c;圆的中心点为(0,0)&#xff0c;圆的半径分别从1到n&#xff0c;而直线都必经过(0,0)点&#xff0c;并且所有直线会把每个圆平均分成2m个面积相等的区域&#xff0c;直线会和圆形成交点&#xff0c;求所有交点两两经…