Python微信订餐小程序课程视频
https://blog.csdn.net/m0_56069948/article/details/122285951
Python实战量化交易理财系统
https://blog.csdn.net/m0_56069948/article/details/122285941
势能线段树(吉司机线段树)
简单介绍和理解
我们知道传统的支持区间修改的线段树,我们都是靠lazylazylazy标记来节省开销的。可以使用lazylazylazy标记必须要满足下面两个条件:
- 区间节点的值可以根据lazylazylazy标记来更新.
- lazylazylazy标记之间可以快速相互合并.
但是很多时候我们要完成的区间修改操作是不能依靠lazylazylazy标记来完成的,比如区间开根号,区间位运算。因为这些运算都是依赖于叶子节点的值的。我们无法直接对lazylazylazy标记或者是区间的值进行修改。但是如果一直无脑递归到叶子节点,一个一个修改的话,显然时间成本我们是无法接受的。所以我们就要使用势能线段树,其实就是类似于在BFS里进行剪枝。我们发现每一个操作,总会使得其能够接受的继续进行修改的次数越来越少,就好像你一开始位于高空,每次修改会让你的高度下降,当你落到地面时,再对你修改就已经没有意义了。就是这个操作对你而言已经"退化"了。
所以我们可以这样来建立和操作这棵线段树:
- 在每个节点额外加入一个"势能标记",来记录和维护当前区间结点的势能情况。
- 对于每次的区间修改,若当前区间内所有结点的势能皆已为零,直接退出递归不再修改.
- 若当前区间内还存在势能不为零的结点,则继续向下递归,暴力修改要求区间内每一个势能不为零的结点.
题目
A. 上帝造题的七分钟 2 / 花神游历各国
链接:
题意:
给定nnn个数,两种操作:
- 区间开根号(向下取整)。
- 区间询问和。
思路:
显然,我们无法使用lazylazylazy标记来节省对区间开根号的开销,因为开根号是由每个叶子节点自己的值决定的。但我们很容易发现当一个数小于等于111以后,再对其开根号是无效的,所以我们可以维护区间最大值作为标记。一旦区间修改时发现此区间的最大值小于等于111时,我们不需要再次修改,直接returnreturnreturn即可,否则继续向下递归修改。
代码:
Copy#include
#define endl '\n'
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const ll N = 2e5 + 10;
const ll INF = 1e18+10;
const ll mod = 1e9+7;
#define ywh666 std::ios::sync\_with\_stdio(false),cin.tie(0),cout.tie(0);
#define all(a) a.begin(),a.end()
struct node{
int l, r;
ll mx, sum;
}tree[4 * N];
ll a[N];
void build(int id, int l, int r){
tree[id].l = l;
tree[id].r = r;
if(l == r){
tree[id].mx = a[l];
tree[id].sum = a[l];
return ;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
tree[id].mx = max(tree[id << 1].mx, tree[id << 1 | 1].mx);
tree[id].sum = tree[id << 1].sum + tree[id << 1 | 1].sum;
}
ll ask(int id, int l, int r){
int L = tree[id].l ;
int R = tree[id].r ;
if(L >= l && R <= r) return tree[id].sum;
int mid = (L + R) >> 1;
ll val = 0;
if(l <= mid) val += ask(id << 1, l, r);
if(r > mid) val += ask(id << 1 | 1, l, r);
return val;
}
void change(int id, int l, int r){
int L = tree[id].l;
int R = tree[id].r;
if(tree[id].mx <= 1) return;
if(L == R) {
tree[id].mx = sqrt(tree[id].mx);
tree[id].sum = tree[id].mx;
return;
}
int mid = (L + R) >> 1;
if(l <= mid ) change(id << 1, l, r);
if(r > mid ) change(id << 1 | 1, l, r);
tree[id].sum = tree[id << 1].sum + tree[id << 1 | 1].sum;
tree[id].mx = max(tree[id << 1].mx, tree[id << 1 | 1].mx);
}
int main(){
ywh666;
ll n ;
cin >> n;
for(int i = 1; i <= n ; i ++) cin >> a[i];
int q;
cin >> q;
build(1, 1, n);
while(q --){
int op, l, r;
cin >> op >> l >> r;
if(l > r) swap(l, r);
if(op == 0){
change(1, l, r);
}el