首页 > 其他分享 >UOJ228/HDU5828 基础数据结构练习题/Rikka with Sequence 题解(势能线段树)

UOJ228/HDU5828 基础数据结构练习题/Rikka with Sequence 题解(势能线段树)

时间:2024-02-23 21:55:23浏览次数:19  
标签:练习题 log min 题解 线段 Sequence sqrt max 节点

势能线段树。如果线段树上一个节点的 \(\max-\min\ge 2\),我们称其为关键节点,考虑定义势能 \(\phi\) 为线段树上关键节点的个数。

对于每次开方操作,如果当前节点为关键节点,则暴力递归左右儿子修改,否则:

  1. 如果当前节点 \(\max=\min\) 或 \(\max=\min+1\) 且 \(\max\) 不是完全平方数,则相当区间覆盖为 \(\sqrt \max\) 或区间减去 \(\sqrt{\max}\)。
  2. 如果当前节点 \(\max=\min+1\) 且 \(\max\) 完全平方数,则相当于区间减 \(\max - \sqrt{\max}\)(因为此时对于最小值,\(\Delta=\min-\sqrt{\min}=\max-\sqrt{\max}\)。

考虑一次区间加操作,最多可以产生 \(O(\log n)\) 个关键区间(由线段树区间加的时间复杂度正确性保证),且对于一个关键区间,我们至多做 \(O(\log \log V)\) 次开方操作,他就不再是一个关键区间(考虑极端情况 \(\min=1,\max=V\))。

于是最终时间复杂度 \(O(n\log n \log \log V)\)。

注意:不能以 \(\sqrt \min\ne\sqrt \max\) 判断是否为关键区间,否则会被 \(8,9,8,9\to2,3,2,3\to8,9,8,9\) 这种数据卡掉。

const int MAXN = 1e5 + 5, inf = MAXN * INT_MAX;
int n, m, a[MAXN];
struct _node {
	int sm, ad, st, mx, mn;
} tr[MAXN << 2];

int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (!isdigit(ch)) {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

void pushup(int p) {
	tr[p].sm = tr[lson].sm + tr[rson].sm;
	tr[p].mx = max(tr[lson].mx, tr[rson].mx);
	tr[p].mn = min(tr[lson].mn, tr[rson].mn);
}

void build(int p, int l, int r) {
	if (l == r) {
		tr[p] = {a[l], 0, inf, a[l], a[l]};
		return;
	}
	tr[p].ad = 0, tr[p].st = inf;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	pushup(p);
}

void addst(int p, int l, int r, int v) {
	tr[p].sm = (r - l + 1) * v;
	tr[p].mx = tr[p].mn = v;
	tr[p].ad = 0;
	tr[p].st = v;
}

void addtg(int p, int l, int r, int v) {
	if (tr[p].st != inf) tr[p].st += v;
	else tr[p].ad += v; 
	tr[p].sm += (r - l + 1) * v;
	tr[p].mx += v;
	tr[p].mn += v;
}

void pushdown(int p, int l, int r) {
	if (tr[p].st != inf) {
		addst(lson, l, mid, tr[p].st);
		addst(rson, mid + 1, r, tr[p].st);
		tr[p].st = inf;
	}
	if (tr[p].ad) {
		addtg(lson, l, mid, tr[p].ad);
		addtg(rson, mid + 1, r, tr[p].ad);
		tr[p].ad = 0;
	}
}

void modify(int p, int l, int r, int L, int R, int x) {
	if (L <= l && r <= R) return addst(p, l, r, x);
	pushdown(p, l, r);
	if (L <= mid) modify(lson, l, mid, L, R, x);
	if (mid < R) modify(rson, mid + 1, r, L, R, x);
	pushup(p); 
}


void modifySqrt(int p, int l, int r, int L, int R) {
	if (L <= l && r <= R && tr[p].mx - tr[p].mn <= 1) {
		const int val = sqrtl(tr[p].mx);
		if (tr[p].mx - tr[p].mn == 1 && val * val == tr[p].mx) return addtg(p, l, r, val - tr[p].mx);
		return addst(p, l, r, val);
	}
	pushdown(p, l, r);
	if (L <= mid) modifySqrt(lson, l, mid, L, R);
	if (mid < R) modifySqrt(rson, mid + 1, r, L, R);
	pushup(p);
}

void add(int p, int l, int r, int L, int R, int x) {
	if (L <= l && r <= R) return addtg(p, l, r, x);
	pushdown(p, l, r);
	if (L <= mid) add(lson, l, mid, L, R, x);
	if (mid < R) add(rson, mid + 1, r, L, R, x);
	pushup(p);
}

int querySum(int p, int l, int r, int L, int R) {
	if (L <= l && r <= R) return tr[p].sm;
	pushdown(p, l, r);
	int ret = 0;
	if (L <= mid) ret += querySum(lson, l, mid, L, R);
	if (mid < R) ret += querySum(rson, mid + 1, r, L, R);
	return ret;
}

void work() {
	n = read(); m = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	build(1, 1, n);
	while (m--) {
		int op, l, r, x;
		op = read(); l = read(); r = read();
		if (op == 1) {
			x = read();
			add(1, 1, n, l, r, x);
		}
		if (op == 2) {
			modifySqrt(1, 1, n, l, r);
		}
		if (op == 3) {
			printf("%lld\n", querySum(1, 1, n, l, r));
		}
	}
}

标签:练习题,log,min,题解,线段,Sequence,sqrt,max,节点
From: https://www.cnblogs.com/XiaoQuQu/p/18030439

相关文章

  • UVA12421 (Jiandan) Mua (I) - Lexical Analyzer 题解
    蒟蒻的第一篇紫题题解!题目传送门思路一眼模拟,还是大模拟。不由得想起了我编了\(4\)个小时的猪国杀……输入首先处理输入,这里我们用一个字符串数组来存储所有的输入,然后再进行处理。while(getline(cin,sr))str[++cnt]=sr+'\n';处理时需要双重循环,注意如果遍历到空格要跳......
  • CF916E Jamie and Tree 题解
    题目链接:CF或者洛谷本题难点在于换根LCA与换根以后的子树范围寻找,重点讲解先说操作一,假如原根为\(1\)变为了\(x\),又变为了\(y\),那么其实\(y\)和\(x\)都可以看做由\(1\)变化而来的,即\(1\rightarrowx\)与\(1\rightarrowy\),原因很简单,我们可以把\(1\rightar......
  • P9901 『PG2』弯曲半平面直线同向图最大流 题解
    思路正解想不出,只好用网络流了网络流简介请戳这儿。这道题数据有点大用EK求最大流似乎过不了,所以本蒟蒻采用Dinic算法。Dinic算法Dinic算法相当于EK的优化。在原基础找增广路的基础上添加了一个分层操作,再通过深搜找阻塞流。分层从原点开始我们把可以通过一步到达的......
  • 在sequence 中 通过后门方式调用task
     可以使用void‘($cast(slaver_drv_use,uvm_top_find("xxxx")));在sequence中调用svt_axi_slave_agent(component) 的task。代码示意 svt_axi_slave_agent   slaver_drv_use;声明句柄void‘($cast(slaver_drv_use,uvm_top_find("uvm_test_top.te_env_inst.amba_s......
  • 记录pyinstaller 打包 pdfplumber 问题解决过程
    今天有一个pdf文件处理需求,使用pdfplumber库完成,python环境是3.11+win10pyinstaller5.10.1打包完成后,工具可以顺利打开,但是执行处理的时候报错File"pypdfium2_raw\bindings.py",line93,in<module>File"pypdfium2_raw\bindings.py",line83,in_register_library......
  • blazor 问题解决
    Cannotprovideavalueforproperty'ScrollToLocationHash'ontype'Microsoft.AspNetCore.Components.Routing.Router'.Thereisnoregisteredserviceoftype'Microsoft.AspNetCore.Components.Routing.IScrollToLocationHash'.异常信息......
  • Jenkins构建提示docker命令权限问题解决方法
    参考:https://zhuanlan.zhihu.com/p/568513293使用Jenkins构建时使用的用户为jenkins在使用docker命令时会报以下错误ERROR:permissiondeniedwhiletryingtoconnecttotheDockerdaemonsocketatunix:///var/run/docker.sock:Get"http://%2Fvar%2Frun%2Fdocker.soc......
  • P6646 [CCO2020] Shopping Plans 题解
    好好玩的题。思路对于前\(K\)小方案问题。我们可以考虑当前方案对下一个方案的转移。重点在于转移的最优化与不重不漏。只有一种种类假设没有\(l,r\)的限制怎么做。我们不妨把所有价格排序。发现一种状态转移到另一种状态,无异与将其中已选择的一个物品不选,选择他后面......
  • process.env.API_KEY undefined问题解决
    问题现象已经在root路径下面创建.env文件,但是使用process.env.API_KEY获取不到值。分析获取不到env文件中的值,检查env文件已配置API_KEY,检查是否安装了dotenv,检查是否导入配置了dotenv解决方法在index.ts中导入import'dotenv/config';应该在使用env的模块前面就导入dote......
  • 2024.2.22模拟赛T3 题解
    对于区间连边,可以线段树优化建图对于单点连边,可以使用李超线段树维护迪杰斯特拉code#include<bits/stdc++.h>usingnamespacestd;#defineN400005#defineintlonglong#definepiipair<int,int>#definefirfirst#definesecsecondintn,m,tot;intval[N];const......