[ABC256Ex] I like Query Problem 题解
[ABC256Ex] I like Query Problem Solution
更好的阅读体验戳此进入
题面
给定
1 L R x
:对于
2 L R y
:区间推平
3 L R
:输出
Solution
显然势能线段树,好像不是很难写。大概就是在一般的线段树基础上维护一个区间数是否均相同的标记,然后区间整除的时候直接通过这个实现 lazytag,这个复杂度经过一系列分析总之最后就是
有区间推平操作,不难想到 ODT,显然会被卡,于是想到一种优化:
考虑这个的时候首先要知道一点语法知识,即对于 set
它是不同于一般的线性结构如 basic_string
的,一般的线性结构当插入删除时若改变 capacity
的话指针就会失效,但当在 set
中插入或删除元素的时候,对于非被删数元素的迭代器、指针和引用等都是不会失效的,用 cppreference 的话来说就是:
No iterators or references are invalidated.
众所周知,我们一般通过对变量的 mutable
修饰以使其可以在 set
中被修改,且按照 l
排序,所以这里我们可以将 r
也修饰为 mutable
,这样的话我们便可以很方便的
然后这样交上去会获得
但是我们可以尝试扩展这种做法,不难想到刚才说的做法复杂度主要浪费在了修改时只修改了一部分,而不需要整棵树重建,所以我们可以尝试在这里优化一下。不难想到,对于一般的线段树,其是支持除了
写在后面
这个奇怪的做法虽然能过,不过还是不推荐写,毕竟实现起来比较复杂细节较多,如果写的话似乎直接写重构部分 ODT 的方法会更好实现一些。一般的线段树写法实现大概也就
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template < typename T = int >
inline T read(void);
int N, Q;
int A[510000];
struct Node{
int l;
mutable int r;
mutable ll val;
friend const bool operator < (const Node &a, const Node &b){
return a.l < b.l;
}
};
class SegTree{
private:
public:
ll tr[510000 << 2];
ll lz[510000 << 2];
#define LS (p << 1)
#define RS (LS | 1)
#define MID ((gl + gr) >> 1)
#define SIZ(l, r) ((r) - (l) + 1)
public:
SegTree(void){memset(lz, -1, sizeof lz);}
void Pushup(int p){tr[p] = tr[LS] + tr[RS];}
void Pushdown(int p, int gl, int gr){
if(!~lz[p])return;
lz[LS] = lz[RS] = lz[p];
tr[LS] = SIZ(gl, MID) * lz[p];
tr[RS] = SIZ(MID + 1, gr) * lz[p];
lz[p] = -1;
}
void Build(int p = 1, int gl = 1, int gr = N){
if(gl == gr)return tr[p] = A[gl = gr], void();
Build(LS, gl, MID), Build(RS, MID + 1, gr);
Pushup(p);
}
void Assign(int l, int r, ll v, int p = 1, int gl = 1, int gr = N){
// printf("Assign ST : l = %d, r = %d, v = %lld, gl = %d, gr = %d, p = %d\n", l, r, v, gl, gr, p);
if(l <= gl && gr <= r)return tr[p] = SIZ(gl, gr) * v, lz[p] = v, void();
Pushdown(p, gl, gr);
if(l <= MID)Assign(l, r, v, LS, gl, MID);
if(MID + 1 <= r)Assign(l, r, v, RS, MID + 1, gr);
Pushup(p);
}
ll Query(int l, int r, int p = 1, int gl = 1, int gr = N){
if(l <= gl && gr <= r)return tr[p];
if(r < gl || l > gr)return 0;
Pushdown(p, gl, gr);
return Query(l, r, LS, gl, MID) + Query(l, r, RS, MID + 1, gr);
}
void Desc(int siz = 3){
int len(1);
int cur(0);
while(siz--){
for(int i = 1; i <= len; ++i)printf("%lld%c", tr[++cur], i == len ? '\n' : ' ');
len <<= 1;
}
}
}st;
class ODT{
private:
set < Node > tr;
public:
auto Insert(Node p){return tr.insert(p);}
auto Split(int p){
auto it = tr.lower_bound(Node{p});
if(it != tr.end() && it->l == p)return it;
advance(it, -1);
if(p > it->r)return tr.end();
int l = it->l, r = it->r;
ll val = it->val;
tr.erase(it);
Insert(Node{l, p - 1, val});
return Insert(Node{p, r, val}).first;
}
void Assign(int l, int r, ll val){
auto itR = Split(r + 1), itL = Split(l);
tr.erase(itL, itR);
Insert(Node{l, r, val});
st.Assign(l, r, val);
}
void Divide(int l, int r, ll x){
auto itR = Split(r + 1), itL = Split(l);
for(auto it = itL; it != itR;){
it->val /= x;
if(!it->val){
decltype(it) nxt;
for(nxt = next(it); nxt != itR; nxt = tr.erase(nxt)){
nxt->val /= x;
if(!nxt->val)it->r = nxt->r;
else{
st.Assign(it->l, it->r, it->val);
st.Assign(nxt->l, nxt->r, nxt->val);
it = next(nxt);
break;
}
}
if(nxt == itR)st.Assign(it->l, it->r, it->val), it = nxt;
}else
st.Assign(it->l, it->r, it->val), advance(it, 1);
}
}
ll Query(int l, int r){
ll ret(0);
auto itR = Split(r + 1), itL = Split(l);
for(auto it = itL; it != itR; ++it)
ret += (it->r - it->l + 1) * it->val;
return ret;
}
void Desc(void){
printf("Describe ODT:\n");
for(auto nod : tr)printf("%d ~ %d : %lld\n", nod.l, nod.r, nod.val);
}
}odt;
int main(){
// freopen("01_n_small_00.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
N = read(), Q = read();
for(int i = 1; i <= N; ++i)odt.Insert(Node{i, i, A[i] = read()});
st.Build();
while(Q--){
int opt = read();
switch(opt){
case 1:{
int l = read(), r = read(), x = read();
odt.Divide(l, r, x);
break;
}
case 2:{
int l = read(), r = read(), x = read();
odt.Assign(l, r, x);
break;
}
case 3:{
int l = read(), r = read();
printf("%lld\n", st.Query(l, r));
break;
}
default: break;
}
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2022_12_08 初稿
update-2022_12_08 修复一点小锅
本文作者:tsawke
本文链接:https://www.cnblogs.com/tsawke/p/17032779.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步