给定
1 L R x:对于
2 L R y:区间推平
3 L R:输出
显然势能线段树,好像不是很难写。大概就是在一般的线段树基础上维护一个区间数是否均相同的标记,然后区间整除的时候直接通过这个实现 lazytag,这个复杂度经过一系列分析总之最后就是
有区间推平操作,不难想到 ODT,显然会被卡,于是想到一种优化:
考虑这个的时候首先要知道一点语法知识,即对于 set 它是不同于一般的线性结构如 basic_string 的,一般的线性结构当插入删除时若改变 capacity 的话指针就会失效,但当在 set 中插入或删除元素的时候,对于非被删数元素的迭代器、指针和引用等都是不会失效的,用 cppreference 的话来说就是:
No iterators or references are invalidated.
众所周知,我们一般通过对变量的 mutable 修饰以使其可以在 set 中被修改,且按照 l 排序,所以这里我们可以将 r 也修饰为 mutable,这样的话我们便可以很方便的
然后这样交上去会获得
但是我们可以尝试扩展这种做法,不难想到刚才说的做法复杂度主要浪费在了修改时只修改了一部分,而不需要整棵树重建,所以我们可以尝试在这里优化一下。不难想到,对于一般的线段树,其是支持除了
这个奇怪的做法虽然能过,不过还是不推荐写,毕竟实现起来比较复杂细节较多,如果写的话似乎直接写重构部分 ODT 的方法会更好实现一些。一般的线段树写法实现大概也就
xxxxxxxxxx186123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22template < typename T = int >23inline T read(void);24
25int N, Q;26int A[510000];27
28struct Node{29 int l;30 mutable int r;31 mutable ll val;32 friend const bool operator < (const Node &a, const Node &b){33 return a.l < b.l;34 }35};36
37class SegTree{38private:39public:40 ll tr[510000 << 2];41 ll lz[510000 << 2];42 43 44 45 46public:47 SegTree(void){memset(lz, -1, sizeof lz);}48 void Pushup(int p){tr[p] = tr[LS] + tr[RS];}49 void Pushdown(int p, int gl, int gr){50 if(!~lz[p])return;51 lz[LS] = lz[RS] = lz[p];52 tr[LS] = SIZ(gl, MID) * lz[p];53 tr[RS] = SIZ(MID + 1, gr) * lz[p];54 lz[p] = -1;55 }56 void Build(int p = 1, int gl = 1, int gr = N){57 if(gl == gr)return tr[p] = A[gl = gr], void();58 Build(LS, gl, MID), Build(RS, MID + 1, gr);59 Pushup(p);60 }61 void Assign(int l, int r, ll v, int p = 1, int gl = 1, int gr = N){62 // printf("Assign ST : l = %d, r = %d, v = %lld, gl = %d, gr = %d, p = %d\n", l, r, v, gl, gr, p);63 if(l <= gl && gr <= r)return tr[p] = SIZ(gl, gr) * v, lz[p] = v, void();64 Pushdown(p, gl, gr);65 if(l <= MID)Assign(l, r, v, LS, gl, MID);66 if(MID + 1 <= r)Assign(l, r, v, RS, MID + 1, gr);67 Pushup(p);68 }69 ll Query(int l, int r, int p = 1, int gl = 1, int gr = N){70 if(l <= gl && gr <= r)return tr[p];71 if(r < gl || l > gr)return 0;72 Pushdown(p, gl, gr);73 return Query(l, r, LS, gl, MID) + Query(l, r, RS, MID + 1, gr);74 }75 void Desc(int siz = 3){76 int len(1);77 int cur(0);78 while(siz--){79 for(int i = 1; i <= len; ++i)printf("%lld%c", tr[++cur], i == len ? '\n' : ' ');80 len <<= 1;81 }82 }83}st;84
85class ODT{86private:87 set < Node > tr;88public:89 auto Insert(Node p){return tr.insert(p);}90 auto Split(int p){91 auto it = tr.lower_bound(Node{p});92 if(it != tr.end() && it->l == p)return it;93 advance(it, -1);94 if(p > it->r)return tr.end();95 int l = it->l, r = it->r;96 ll val = it->val;97 tr.erase(it);98 Insert(Node{l, p - 1, val});99 return Insert(Node{p, r, val}).first;100 }101 void Assign(int l, int r, ll val){102 auto itR = Split(r + 1), itL = Split(l);103 tr.erase(itL, itR);104 Insert(Node{l, r, val});105 st.Assign(l, r, val);106 }107 void Divide(int l, int r, ll x){108 auto itR = Split(r + 1), itL = Split(l);109 for(auto it = itL; it != itR;){110 it->val /= x;111 if(!it->val){112 decltype(it) nxt;113 for(nxt = next(it); nxt != itR; nxt = tr.erase(nxt)){114 nxt->val /= x;115 if(!nxt->val)it->r = nxt->r;116 else{117 st.Assign(it->l, it->r, it->val);118 st.Assign(nxt->l, nxt->r, nxt->val);119 it = next(nxt);120 break;121 }122 }123 if(nxt == itR)st.Assign(it->l, it->r, it->val), it = nxt;124 }else125 st.Assign(it->l, it->r, it->val), advance(it, 1);126 }127 }128 ll Query(int l, int r){129 ll ret(0);130 auto itR = Split(r + 1), itL = Split(l);131 for(auto it = itL; it != itR; ++it)132 ret += (it->r - it->l + 1) * it->val;133 return ret;134 }135 void Desc(void){136 printf("Describe ODT:\n");137 for(auto nod : tr)printf("%d ~ %d : %lld\n", nod.l, nod.r, nod.val);138 }139}odt;140
141int main(){142 // freopen("01_n_small_00.txt", "r", stdin);143 // freopen("out.txt", "w", stdout);144 N = read(), Q = read();145 for(int i = 1; i <= N; ++i)odt.Insert(Node{i, i, A[i] = read()});146 st.Build();147 while(Q--){148 int opt = read();149 switch(opt){150 case 1:{151 int l = read(), r = read(), x = read();152 odt.Divide(l, r, x);153 break;154 }155 case 2:{156 int l = read(), r = read(), x = read();157 odt.Assign(l, r, x);158 break;159 }160 case 3:{161 int l = read(), r = read();162 printf("%lld\n", st.Query(l, r));163 break;164 }165 default: break;166 }167 }168 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);169 return 0;170}171
172template < typename T >173inline T read(void){174 T ret(0);175 int flag(1);176 char c = getchar();177 while(c != '-' && !isdigit(c))c = getchar();178 if(c == '-')flag = -1, c = getchar();179 while(isdigit(c)){180 ret *= 10;181 ret += int(c - '0');182 c = getchar();183 }184 ret *= flag;185 return ret;186}update-2022_12_08 初稿
update-2022_12_08 修复一点小锅