数据结构之线段树合并——永无乡,Lomsat gelral,Tree Rotations,Tree Rotations Escape Through Leaf

文章目录

  • [HNOI2012]永无乡
  • Lomsat gelral
  • 「POI2011 R2 Day2」旋转树木 Tree Rotations
  • Escape Through Leaf

线段树合并与 fhq-treap合并很类似,也是将两个不同根的线段树暴力合并

至于时间复杂度,线段树合并一次是可以达到O(n)O(n)O(n)的,但是大家都是算平摊复杂度的,平摊后就是log⁡\loglog级别了

int merge( int x, int y, int l, int r ) {if( ! x or ! y ) return x + y;if( l == r ) { //操作一下return x;}int mid = ( l + r ) >> 1;t[x].l = merge( t[x].l, t[y].l, l, mid );t[x].r = merge( t[x].r, t[y].r, mid + 1, r );//再合并操作一下return x;
}

如果是树的线段树合并

就是先操作完儿子,再插入父亲

void dfs( int u, int fa ) {for( auto v : G[u] ) {if( v == fa ) continue;else dfs( v, u );root[u] = merge( root[u], root[v], 1, n );}//可能还有点操作modify( root[u], 1, n, [] );
}

[HNOI2012]永无乡

BZOJ2733

初始每个岛屿自己是一个连通块,自己单开一个权值线段树(使用动态开点)

然后就很暴力,利用并查集可以判断那两个岛屿是否已经在一个连通块

不在就直接线段树合并,在就不管

查询就找到其所在连通块的线段树,直接查就是了

#include <cstdio>
#define maxn 100005
struct node { int l, r, id, tot; }t[maxn * 50];
int f[maxn], root[maxn];
int n, m, cnt;int find( int x ) { return x == f[x] ? x : f[x] = find( f[x] ); }void modify( int &now, int l, int r, int pos, int id ) {if( ! now ) now = ++ cnt;if( l == r ) { t[now].id = id, t[now].tot ++; return; }int mid = ( l + r ) >> 1;if( pos <= mid ) modify( t[now].l, l, mid, pos, id );else modify( t[now].r, mid + 1, r, pos, id );t[now].tot = t[t[now].l].tot + t[t[now].r].tot;
}int merge( int x, int y, int l, int r ) {if( ! x or ! y ) return x + y;if( l == r ) { if( t[y].id ) t[x].id = t[y].id;t[x].tot += t[y].tot;return x;}int mid = ( l + r ) >> 1;t[x].l = merge( t[x].l, t[y].l, l, mid );t[x].r = merge( t[x].r, t[y].r, mid + 1, r );t[x].tot = t[t[x].l].tot + t[t[x].r].tot;return x;
}int query( int now, int k, int l, int r ) {if( ! now or t[now].tot < k ) return -1;int mid = ( l + r ) >> 1;if( l == r ) return t[now].id;if( t[t[now].l].tot >= k ) return query( t[now].l, k, l, mid );else return query( t[now].r, k - t[t[now].l].tot, mid + 1, r );
}int main() {scanf( "%d %d", &n, &m );for( int i = 1, x;i <= n;i ++ ) {scanf( "%d", &x );modify( root[i], 1, n, x, i );f[i] = i;}for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );u = find( u );v = find( v );f[v] = u;root[u] = merge( root[u], root[v], 1, n );}char opt[10]; int x, y, Q;scanf( "%d", &Q );while( Q -- ) {scanf( "%s %d %d", opt, &x, &y );if( opt[0] == 'B' ) {x = find( x );y = find( y );if( x == y ) continue;else f[y] = x, root[x] = merge( root[x], root[y], 1, n );}else {x = find( x );printf( "%d\n", query( root[x], y, 1, n ) );}}return 0;
}

Lomsat gelral

CF600E

dfs先操作儿子,儿子操作完后并到父亲线段树内

线段树维护区间颜色出现最大值,和颜色编号和,基操

#include <cstdio>
#include <vector>
using namespace std;
#define maxn 100005
#define int long long
vector < int > G[maxn];
struct node { int l, r, Max, sum; }t[maxn * 50];
int cnt, n;
int c[maxn], root[maxn];void pushup( int now ) {if( t[t[now].l].Max > t[t[now].r].Max ) {t[now].Max = t[t[now].l].Max;t[now].sum = t[t[now].l].sum;}else if( t[t[now].l].Max < t[t[now].r].Max ) {t[now].Max = t[t[now].r].Max;t[now].sum = t[t[now].r].sum;}else {t[now].Max = t[t[now].l].Max;t[now].sum = t[t[now].l].sum + t[t[now].r].sum;}
}void modify( int &now, int l, int r, int pos ) {if( ! now ) now = ++ cnt;if( l == r ) { t[now].Max ++, t[now].sum = l; return; }int mid = l + r >> 1;if( pos <= mid ) modify( t[now].l, l, mid, pos );else modify( t[now].r, mid + 1, r, pos );pushup( now );
}int merge( int now, int lst, int l, int r ) {if( ! now or ! lst ) return now + lst;if( l == r ) { t[now].Max += t[lst].Max; return now; }int mid = l + r >> 1;t[now].l = merge( t[now].l, t[lst].l, l, mid );t[now].r = merge( t[now].r, t[lst].r, mid + 1, r );pushup( now );return now;
}void dfs( int u, int fa ) {for( auto v : G[u] ) {if( v == fa ) continue;else dfs( v, u );root[u] = merge( root[u], root[v], 1, n );}modify( root[u], 1, n, c[u] );
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%lld", &c[i] );root[i] = i;cnt ++;}for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );  }dfs( 1, 0 );for( int i = 1;i <= n;i ++ )printf( "%lld ", t[root[i]].sum );return 0;
}

「POI2011 R2 Day2」旋转树木 Tree Rotations

LOJ2163

性质:考虑相同长度的不交的两段x,yx,yx,y要计算逆序对,则xxx再分成相同长度不交的两段a,ba,ba,b

不管是a,ba,ba,b还是b,ab,ab,axxxyyy的逆序对(一个来自xxx,一个来自yyy)数量不会变

因为换不换,都是在yyy前面

这就可以用线段树维护,这个性质意味着儿子换不换,对父亲与其他父亲间的计算没有影响

所以建立权值线段树,直接对于每一层线段树合并

先计算左右儿子不换,和换的逆序对,再合并

合并完后,选择更小的方案

#include <cstdio>
#include <iostream>
using namespace std;
#define maxn 200005
#define int long long
struct node { int l, r, ans; }t[maxn * 50];
int cnt, nxd1, nxd2;void modify( int &now, int l, int r, int pos ) {if( ! now ) now = ++ cnt;t[now].ans ++;if( l == r ) return;int mid = l + r >> 1;if( pos <= mid ) modify( t[now].l, l, mid, pos );else modify( t[now].r, mid + 1, r, pos );
}int merge( int x, int y, int l, int r ) {if( ! x or ! y ) return x + y;t[x].ans += t[y].ans;if( l == r ) return x;int mid = l + r >> 1;nxd1 += t[t[x].r].ans * t[t[y].l].ans;nxd2 += t[t[x].l].ans * t[t[y].r].ans;t[x].l = merge( t[x].l, t[y].l, l, mid );t[x].r = merge( t[x].r, t[y].r, mid + 1, r );return x;
}int n, x, ans, node;
int root[maxn];
void dfs( int &k ) {scanf( "%lld", &x );if( x ) {k = ++ node;modify( root[k], 1, n, x );return;}int l, r;dfs( l );dfs( r );nxd1 = 0;nxd2 = 0;merge( root[l], root[r], 1, n );ans += min( nxd1, nxd2 );k = l;
}signed main() {scanf( "%lld", &n );dfs( n );printf( "%lld\n", ans );return 0;
}

Escape Through Leaf

CF932F

首先,有个简单的n2n^2n2dpdpdp:设dpu:udp_u:udpu:u的答案,则dpu=min⁡{dpv+av∗bu}v∈sonudp_u=\min\{dp_v+a_v*b_u\}\quad v\in son_udpu=min{dpv+avbu}vsonu

这完完全全就是李超线段树的长相

直接dfs树合并李超线段树

考虑两条直线的合并,t[x]表示原先已有的直线,now表示这一次新加的直线

  • 新直线的斜率更大,判断在mid处两条直线的值大小

    • 新直线更小

      在这里插入图片描述

      原直线可能在mid右边有贡献,继续修改右儿子,并且mid处的直线被更新成新直线

    • 新直线更大

      在这里插入图片描述

      新直线可能在mid左边有贡献,继续修改左儿子,并且mid处的直线不会被更新

  • 新直线的斜率更小,判断在mid处两条直线的值大小

    • 新直线更小

      在这里插入图片描述

      原直线可能在mid左边有贡献,继续修改左儿子,并且mid处的直线被更新成新直线

    • 新直线更大

      在这里插入图片描述

      新直线可能在mid右边有贡献,继续修改右儿子,并且mid处的直线不会被更新

  • 斜率相同

    在这里插入图片描述

    直接判断截距的大小,选择截距小的直线,直接覆盖完

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 100005
#define int long long
vector < int > G[maxn];
struct node { int k, b; }t[maxn * 50];
int a[maxn], b[maxn], root[maxn], ans[maxn], lson[maxn * 50], rson[maxn * 50];
int n, cnt;int calc( node l, int x ) { return l.k * x + l.b; }void modify( int &x, int l, int r, node now ) {if( ! x ) { t[x = ++ cnt] = now; return; }if( l == r ) { t[x] = calc( t[x], l ) < calc( now, l ) ? t[x] : now; return; }int mid = ( l + r ) >> 1;if( now.k > t[x].k ) {if( calc( now, mid ) <= calc( t[x], mid ) ) modify( rson[x], mid + 1, r, t[x] ), t[x] = now;else modify( lson[x], l, mid, now );}else if( now.k < t[x].k ) {if( calc( now, mid ) <= calc( t[x], mid ) )modify( lson[x], l, mid, t[x] ), t[x] = now;elsemodify( rson[x], mid + 1, r, now );}else if( now.b < t[x].b ) t[x] = now;
}int query( int now, int l, int r, int x ) {if( ! now ) return 1e18;if( l == r ) return calc( t[now], x );int mid = ( l + r ) >> 1, ret;if( x <= mid ) ret = query( lson[now], l, mid, x );else ret = query( rson[now], mid + 1, r, x );return min( ret, calc( t[now], x ) );
}int merge( int x, int y, int l, int r ) {if( ! x or ! y ) return x + y;if( l == r ) { return calc( t[x], l ) < calc( t[y], l ) ? x : y; }int mid = ( l + r ) >> 1;lson[x] = merge( lson[x], lson[y], l, mid );rson[x] = merge( rson[x], rson[y], mid + 1, r );modify( x, l, r, t[y] );return x;
}void dfs( int u, int fa ) {bool flag = 0;for( auto v : G[u] ) {if( v == fa ) continue;else dfs( v, u );flag = 1;root[u] = merge( root[u], root[v], -1e5, 1e5 );}node line;line.k = b[u];if( flag ) ans[u] = line.b = query( root[u], -1e5, 1e5, a[u] );else ans[u] = line.b = 0;modify( root[u], -1e5, 1e5, line );
}signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &b[i] );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u ); }dfs( 1, -1 );for( int i = 1;i <= n;i ++ ) printf( "%lld ", ans[i] );return 0;
}

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

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

相关文章

吉特仓储管理系统--开源2018年源码

应该说今天过完&#xff0c;这个年就算真正意义上的过完了&#xff0c;没有想到的是又是在出差的路上写这样的文章。废话也不多说&#xff0c;写这篇文章主要的目的是想将去年吉特仓储管理系统开发的一个版本源代码开放出来&#xff0c;供各位开发者阅读使用。github 源代码地址…

自定义Visual Studio.net Extensions 开发符合ABP vnext框架代码生成插件[附源码]

介绍我很早之前一直在做mvc5 scaffolder的开发功能做的已经非常完善,使用代码对mvc5的项目开发效率确实能成倍的提高,就算是刚进团队的新成员也能很快上手,如果你感兴趣 可以参考 http://neozhu.github.io/MVC5-Scaffolder/#/ https://github.com/neozhu/MVC5-Scaffolder但是m…

洛谷P1650:田忌赛马(贪心)

解析 其实并不简单的一道题。 是刘汝佳老师的例题&#xff0c;搜到之后按照讲的策略写了一发。 &#xff08;由于这个策略并不完全正确&#xff0c;就不展开讲了&#xff09; 好啊&#xff01; 可是感觉讲的策略特别对&#xff0c;为什么呢&#xff1f; 原因在于&#xff0…

EFCore Lazy Loading + Inheritance = 干净的数据表 (二)

前言本篇是上一篇EFCore Lazy Loading Inheritance 干净的数据表 &#xff08;一&#xff09; 【献给处女座的DB First程序猿】 前菜 的续篇。这一篇才是真的为处女座的DB First程序猿准备的正餐。继续上一篇的话题&#xff0c;我们希望用EFCore&#xff0c;且继续使用与逻辑…

我们为什么要搞长沙.NET技术社区?

某种意义上讲&#xff0c;长沙和中国大部分内地城市一样&#xff0c;都是互联网时代的灯下黑。没有真正意义上的互联网公司&#xff0c;例如最近发布的中国互联网企业一百强中没有一家湖南或者长沙的公司就是明证。然而长沙并非没有互联网人&#xff0c;在麓谷几十万计的IT 从业…

在ASP.NET Core中使用EPPlus导入出Excel文件

这篇文章说明了如何使用EPPlus在ASP.NET Core中导入和导出.xls/.xlsx文件&#xff08;Excel&#xff09;。在考虑使用.NET处理excel时&#xff0c;我们总是寻找第三方库或组件。使用Open Office Xml格式&#xff08;xlsx&#xff09;读取和写入Excel 2007/2010文件的最流行的.n…

月旦评 之 DevOps招贤令2019 - 没有人比我们更懂DevOps

公元164-182年间&#xff0c;汝南平舆的许氏兄弟于每月初一品评人物&#xff0c;褒贬时政&#xff0c;被称为“月旦评”。所谓“子治世之能臣&#xff0c;乱世之奸雄也”这句许邵评价曹操的话也是来自于“月旦评”&#xff1b;时间一下子来到了2019年&#xff0c;DevOps招贤令再…

HDU - 2204 Eddy‘s爱好(尚未完全解决)

HDU - 2204 Eddy’s爱好 题意&#xff1a; 给你一个正整数N&#xff0c;确定在1到N之间有多少个可以表示成M^K&#xff08;K>1)的数 题解&#xff1a; 参考题解&#xff1a; 我们先举例找找规律 1~10以内2的次方有多少个&#xff1f;有121,224,329,一共三个&#xff0c;…

EF Core中避免贫血模型的三种行之有效的方法(翻译)

[Paul Hiles: 3 ways to avoid an anemic domain model in EF Core &#xff1a;https://www.devtrends.co.uk/blog/3-ways-to-avoid-an-anemic-domain-model-in-ef-core]1.引言在使用ORM中&#xff08;比如Entity Framework&#xff09;贫血领域模型十分常见 。本篇文章将先探…

Saving Beans HDU - 3037(卢卡斯定理)

Saving Beans HDU - 3037&#xff08;卢卡斯定理&#xff09; 题意&#xff1a; 他们想知道有多少种方法可以在n树中保存不超过m个bean&#xff08;它们是相同的&#xff09;。 现在他们求助于你&#xff0c;你应该给他们答案。 结果可能非常巨大; 你应该输出模p的结果&…

我们为什么要搞长沙.NET技术社区(三)

我们为什么要搞长沙.NET技术社区&#xff08;三&#xff09; 小饭局搞事情先从饭局开始是中华民族的优良传统。昨天晚餐时间&#xff0c;长沙 .net 技术社区的主要发起人员进行了一番小聚&#xff0c;同时也作为一个非正式会议&#xff0c;对社区发展进行了探讨。从介绍自己对于…

【招聘(北京)】北森测评招聘 .NET 架构师、高级工程师

工作职责公司核心产品的迭代需求分析设计开发。公司核心产品的线上维护和性能调优。对初中级技术人员培养和质量把关。编写软件设计和技术文档。任职资格为人正直、诚信、责任心强&#xff0c;能承受较大工作压力。强烈的目标导向意识&#xff0c;逻辑思维清晰&#xff0c;执行…

网络流模型与技巧总结

文章目录前言常见基本模型最大匹配、最小点覆盖和最大独立集构造最小点覆盖最大点权匹配最小路径覆盖不可重覆盖可重覆盖最大权闭合子图建图技巧利用拆点进行限流利用断边表示决策利用虚点表示组合关系链状模型用链表示时间轴用链表示偏序关系形式的选取限制通过拆点描述先后顺…

卢卡斯定理 Lucas

参考文章 详细定义内容看这个参考文章 结论&#xff1a; 模板&#xff1a; Lucas函数&#xff1a; long long Lucas(long long n,long long m){if(m0) return 1;return Lucas(n/p,m/p)*C(n%p,m%p)%p; }组合数函数&#xff1a; 此处求逆元的用的bp-2 long long C(long long…

VS 2019 要来了,是时候了解一下 C# 8.0 新功能

近日&#xff0c;微软发布了 Visual Studio 2019 的发布日期&#xff0c;2019 年 4 月 2 日 Visual Studio 2019 将正式和大家见面&#xff0c;同时微软还将提供发布现场实时直播。除了 Visual Studio 2019 自身之外&#xff0c;VS 2019 的发布还牵动着很多 C# 开发者的心。虽然…

[蓝桥杯2020国赛]游园安排

题目&#xff1a; 题解&#xff1a; 本质就是求最长上升子序列&#xff0c;只不过这里是字符串版本的&#xff0c;我们都知道有n^2的LIS&#xff0c;但其实还有O(nlogn)版本的&#xff0c;详细看这里&#xff0c;套上就行 另外我发现这里竟然有蓝桥杯全套的编程题离谱&#xf…

重新解读DDD领域驱动设计(一)

回顾十年前&#xff0c;还未踏入某校时&#xff0c;便听闻某学长一毕业就入职北京某公司&#xff0c;月薪过万。对于一个名不见经传的小学院&#xff0c;一毕业能拿到这个薪水还是非常厉害的。听闻他学生期间参与开发了一款股票软件&#xff0c;股票那时正迎来一波疯涨。时也运…

程序员修神之路--高并发优雅的做限流(有福利)

点击上方蓝色字体&#xff0c;关注我们菜菜哥&#xff0c;有时间吗&#xff1f;YY妹&#xff0c;什么事&#xff1f;我最近的任务是做个小的秒杀活动&#xff0c;我怕把后端接口压垮&#xff0c;X总说这可关系到公司的存亡简单呀&#xff0c;你就做个限流呗这个没做过呀&#x…

免费馅饼 HDU - 1176

免费馅饼 HDU - 1176 题意&#xff1a; 都说天上不会掉馅饼&#xff0c;但有一天gameboy正走在回家的小径上&#xff0c;忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了&#xff0c;这馅饼别处都不掉&#xff0c;就掉落在他身旁的10米范围内。馅饼如果掉在了地上…

微软 HoloLens 2 正式登场!让你看看什么叫真正的黑科技

北京时间 2 月 25 日凌晨消息&#xff0c;微软在 MWC19 举行新品发布会&#xff0c;正式发布了万众期待的 HoloLens 2 等产品。▲ 认识全新的 Microsoft HoloLens 2微软 HoloLens 全息眼镜是微软推出的一款头戴式混合现实装置&#xff0c;可以完全独立使用&#xff0c;无需线缆…